diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml
new file mode 100644
index 0000000..e4e7c75
--- /dev/null
+++ b/.github/workflows/build-macos.yml
@@ -0,0 +1,65 @@
+name: build-macos
+
+on:
+ push:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - "master"
+ pull_request:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - master
+
+jobs:
+ build-and-test:
+ runs-on: macos-10.15
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Init
+ run: chmod +x ./build.sh
+
+ - name: Install NuGet
+ uses: NuGet/setup-nuget@v1.0.5
+
+ - name: Setup Testspace
+ uses: testspace-com/setup-testspace@v1
+ with:
+ domain: ${{github.repository_owner}}
+
+ - name: Install .NET 3.1
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "3.1.x"
+
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "5.0.x"
+
+ - name: Install .NET 6
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "6.0.x"
+
+ - name: Install .NET 7
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "7.0.x"
+
+ - name: Build
+ run: ./build.sh --target build
+
+ - name: Run Tests
+ run: ./build.sh --target tests --exclusive
+
+ - name: Push result to Testspace server
+ run: |
+ testspace [macos]**/*.trx
+ if: always()
diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml
new file mode 100644
index 0000000..3f65d18
--- /dev/null
+++ b/.github/workflows/build-ubuntu.yml
@@ -0,0 +1,65 @@
+name: build-ubuntu
+
+on:
+ push:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - "master"
+ pull_request:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - master
+
+jobs:
+ build-and-test:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Init
+ run: chmod +x ./build.sh
+
+ - name: Install NuGet
+ uses: NuGet/setup-nuget@v1.0.5
+
+ - name: Setup Testspace
+ uses: testspace-com/setup-testspace@v1
+ with:
+ domain: ${{github.repository_owner}}
+
+ - name: Install .NET 3.1
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "3.1.x"
+
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "5.0.x"
+
+ - name: Install .NET 6
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "6.0.x"
+
+ - name: Install .NET 7
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "7.0.x"
+
+ - name: Build
+ run: ./build.sh --target build
+
+ - name: Run Tests
+ run: ./build.sh --target tests --exclusive
+
+ - name: Push result to Testspace server
+ run: |
+ testspace [linux]**/*.trx
+ if: always()
diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml
new file mode 100644
index 0000000..9632c06
--- /dev/null
+++ b/.github/workflows/build-windows.yml
@@ -0,0 +1,59 @@
+name: build-windows
+
+on:
+ push:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - "master"
+ pull_request:
+ paths-ignore:
+ - "**.md"
+ - LICENSE
+ branches:
+ - master
+
+jobs:
+ build-and-test:
+ runs-on: windows-2019
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Setup Testspace
+ uses: testspace-com/setup-testspace@v1
+ with:
+ domain: ${{github.repository_owner}}
+
+ - name: Install .NET 3.1
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "3.1.x"
+
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "5.0.x"
+
+ - name: Install .NET 6
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "6.0.x"
+
+ - name: Install .NET 7
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "7.0.x"
+
+ - name: Build
+ run: .\build.ps1 --target build
+
+ - name: Run Tests
+ run: .\build.ps1 --target tests --exclusive
+
+ - name: Push result to Testspace server
+ run: |
+ testspace [windows]**/*.trx
+ if: always()
diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
new file mode 100644
index 0000000..a4f655f
--- /dev/null
+++ b/.github/workflows/publish-nuget.yml
@@ -0,0 +1,75 @@
+name: "publish-nuget"
+
+on:
+ workflow_dispatch:
+ inputs:
+ package-version:
+ description: "Package Version"
+ required: true
+ package-source:
+ type: choice
+ description: Package Source
+ required: true
+ default: "myget"
+ options:
+ - myget
+ - nuget
+ package-id:
+ type: choice
+ description: Package Id
+ required: true
+ default: "LocalStack.AwsLocal"
+ options:
+ - LocalStack.AwsLocal
+
+jobs:
+ publish-nuget:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Init
+ run: chmod +x ./build.sh
+
+ - name: Install NuGet
+ uses: NuGet/setup-nuget@v1.0.5
+
+ - name: Install .NET 3.1
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "3.1.x"
+
+ - name: Install .NET 5
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "5.0.x"
+
+ - name: Install .NET 6
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "6.0.x"
+
+ - name: Install .NET 7
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: "7.0.x"
+
+ - name: Build & Test
+ run: ./build.sh
+
+ - name: "Print Version"
+ run: |
+ echo "Package Version: ${{ github.event.inputs.package-version }}"
+
+ - name: Nuget Pack
+ run: ./build.sh --target nuget-pack --package-source ${{ github.event.inputs.package-source }} --package-id ${{ github.event.inputs.package-id }} --package-version ${{ github.event.inputs.package-version }}
+
+ - name: MyGet Push
+ if: ${{ github.event.inputs.package-source == 'myget' }}
+ run: ./build.sh --target nuget-push --package-source ${{ github.event.inputs.package-source }} --package-id ${{ github.event.inputs.package-id }} --package-version ${{ github.event.inputs.package-version }} --package-secret ${{secrets.MYGET_API_KEY}}
+
+ - name: NuGet Push
+ if: ${{ github.event.inputs.package-source == 'nuget' }}
+ run: ./build.sh --target nuget-push --package-source ${{ github.event.inputs.package-source }} --package-id ${{ github.event.inputs.package-id }} --package-version ${{ github.event.inputs.package-version }} --package-secret ${{secrets.NUGET_API_KEY}}
diff --git a/build.ps1 b/build.ps1
index dc223b7..455c631 100644
--- a/build.ps1
+++ b/build.ps1
@@ -1,128 +1,3 @@
-##########################################################################
-# This is the Cake bootstrapper script for PowerShell.
-# This file is based on https://github.com/cake-build/resources modified for Cake.CoreCLR
-# Feel free to change this file to fit your needs.
-##########################################################################
-
-<#
-.SYNOPSIS
-This is a Powershell script to bootstrap a Cake build.
-.DESCRIPTION
-This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
-and execute your Cake build script with the parameters you provide.
-.PARAMETER Script
-The build script to execute.
-.PARAMETER Target
-The build script target to run.
-.PARAMETER Configuration
-The build configuration to use.
-.PARAMETER Verbosity
-Specifies the amount of information to be displayed.
-.PARAMETER ShowDescription
-Shows description about tasks.
-.PARAMETER DryRun
-Performs a dry run.
-.PARAMETER Experimental
-Uses the nightly builds of the Roslyn script engine.
-.PARAMETER Mono
-Uses the Mono Compiler rather than the Roslyn script engine.
-.PARAMETER SkipToolPackageRestore
-Skips restoring of packages.
-.PARAMETER ScriptArgs
-Remaining arguments are added here.
-.LINK
-https://cakebuild.net
-#>
-
-[CmdletBinding()]
-Param(
- [string]$Script = "build.cake",
- [string]$Target,
- [string]$Configuration,
- [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
- [string]$Verbosity,
- [switch]$ShowDescription,
- [Alias("WhatIf", "Noop")]
- [switch]$DryRun,
- [switch]$Experimental,
- [switch]$Mono,
- [switch]$SkipToolPackageRestore,
- [Parameter(Position = 0, Mandatory = $false, ValueFromRemainingArguments = $true)]
- [string[]]$ScriptArgs
-)
-
-Write-Host "Preparing to run build script..."
-
-if (!$PSScriptRoot) {
- $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
-}
-
-$CAKE_VERSION = "0.37.0"
-
-$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
-$CAKE_ROOT = Join-Path $TOOLS_DIR "/cake.coreclr/"
-$CAKE_EXE = Join-Path $CAKE_ROOT "/Cake.dll"
-
-# Make sure that dotnet core installed.
-try {
- dotnet --version
-}
-catch {
- Throw "Error: dotnet is not installed."
-}
-
-# Install cake if its not installed
-if (!(Test-Path $CAKE_EXE)) {
- # Make sure tools folder exists
- if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
- Write-Verbose -Message "Creating tools directory..."
- New-Item -Path $TOOLS_DIR -Type directory | out-null
- }
-
- # Make sure that tools.csproj exist.
- if (!(Test-Path "$TOOLS_DIR/tools.csproj")) {
- Write-Verbose -Message "Creating tools.csproj..."
- try {
- New-Item "$TOOLS_DIR/tools.csproj" -ItemType file
- "Exenetcoreapp3.1" | Out-File -FilePath "$TOOLS_DIR/tools.csproj" -Append
- }
- catch {
- Throw "Could not download packages.config."
- }
- }
-
- $CAKE_NFW = Join-Path $TOOLS_DIR "/cake/"
-
- # Add dependencies
- dotnet add $TOOLS_DIR/tools.csproj package Cake.CoreCLR -v $CAKE_VERSION --package-directory $TOOLS_DIR
- # Add Cake.exe for VsCode intellisense support
- dotnet add $TOOLS_DIR/tools.csproj package Cake -v $CAKE_VERSION --package-directory $TOOLS_DIR
-
- # Clean up
- Move-Item -Path $CAKE_ROOT/$CAKE_VERSION/* -Destination $CAKE_ROOT
- Remove-Item $CAKE_ROOT/$CAKE_VERSION/ -Force -Recurse
- Move-Item -Path $CAKE_NFW/$CAKE_VERSION/* -Destination $CAKE_NFW
- Remove-Item $CAKE_NFW/$CAKE_VERSION/ -Force -Recurse
- Remove-Item $TOOLS_DIR/tools.csproj
-}
-
-# Make sure that Cake has been installed.
-if (!(Test-Path $CAKE_EXE)) {
- Throw "Could not find Cake.dll at $CAKE_EXE"
-}
-
-# Build Cake arguments
-$cakeArguments = @("$Script");
-if ($Target) { $cakeArguments += "-target=$Target" }
-if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
-if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
-if ($ShowDescription) { $cakeArguments += "-showdescription" }
-if ($DryRun) { $cakeArguments += "-dryrun" }
-if ($Experimental) { $cakeArguments += "-experimental" }
-if ($Mono) { $cakeArguments += "-mono" }
-$cakeArguments += $ScriptArgs
-
-# Start Cake
-Write-Host "Running build script..."
-&dotnet $TOOLS_DIR/cake.coreclr/Cake.dll $cakeArguments
-exit $LASTEXITCODE
\ No newline at end of file
+dotnet build ./build/LocalStack.Build/LocalStack.Build.csproj >$null 2>&1
+dotnet run --project ./build/LocalStack.Build/LocalStack.Build.csproj --no-launch-profile --no-build -- $args
+exit $LASTEXITCODE;
\ No newline at end of file
diff --git a/build.sh b/build.sh
index 739b42e..2b2c46b 100644
--- a/build.sh
+++ b/build.sh
@@ -1,78 +1,2 @@
-#!/usr/bin/env bash
-
-##########################################################################
-# This is the Cake bootstrapper script for Linux and OS X.
-# This file is based on https://github.com/cake-build/resources modified for Cake.CoreCLR
-# Feel free to change this file to fit your needs.
-##########################################################################
-
-CAKE_VERSION=0.37.0
-
-# Define directories.
-SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-TOOLS_DIR=$SCRIPT_DIR/tools
-CAKE_ROOT= $TOOLS_DIR/cake.coreclr/
-CAKE_EXE=$TOOLS_DIR/cake.coreclr/Cake.dll
-
-# Define default arguments.
-SCRIPT="build.cake"
-TARGET="Default"
-CONFIGURATION="Release"
-VERBOSITY="verbose"
-DRYRUN=
-SHOW_VERSION=false
-CAKE_ARGUMENTS=()
-
-# Parse arguments.
-for i in "$@"; do
- case $1 in
- -s|--script) SCRIPT="$2"; shift ;;
- --) shift; CAKE_ARGUMENTS+=("$@"); break ;;
- *) CAKE_ARGUMENTS+=("$1") ;;
- esac
- shift
-done
-
-# Make sure that dotnet core installed.
-if ! [ -x "$(command -v dotnet)" ]; then
- echo 'Error: dotnet is not installed.' >&2
- exit 1
-fi
-
-# Install cake if its not installed
-if [ ! -f "$CAKE_EXE" ]; then
-
- # Make sure the tools folder exist.
- if [ ! -d "$TOOLS_DIR" ]; then
- mkdir "$TOOLS_DIR"
- fi
-
- # Make sure that tools.csproj exist.
- if [ ! -f "$TOOLS_DIR/tools.csproj" ]; then
- echo "Creating tools.csproj..."
- echo "Exenetcoreapp3.1" > $TOOLS_DIR/tools.csproj
- if [ $? -ne 0 ]; then
- echo "An error occurred while creating tools.csproj."
- exit 1
- fi
- fi
-
- # Add dependencies
- dotnet add $TOOLS_DIR/tools.csproj package Cake.CoreCLR -v $CAKE_VERSION --package-directory $TOOLS_DIR
- mv $TOOLS_DIR/cake.coreclr/$CAKE_VERSION/* $TOOLS_DIR/cake.coreclr/
- rm -rf $TOOLS_DIR/cake.coreclr/$CAKE_VERSION/
- rm -f $TOOLS_DIR/tools.csproj
-fi
-
-# Make sure that Cake has been installed.
-if [ ! -f "$CAKE_EXE" ]; then
- echo "Could not find Cake.exe at '$CAKE_EXE'."
- exit 1
-fi
-
-# Start Cake
-if $SHOW_VERSION; then
- dotnet $TOOLS_DIR/cake.coreclr/Cake.dll -version
-else
- dotnet $TOOLS_DIR/cake.coreclr/Cake.dll $SCRIPT "${CAKE_ARGUMENTS[@]}"
-fi
\ No newline at end of file
+dotnet build ./build/LocalStack.Build/LocalStack.Build.csproj > /dev/null 2>&1
+dotnet run --project ./build/LocalStack.Build/LocalStack.Build.csproj --no-launch-profile --no-build -- "$@"
diff --git a/build/LocalStack.Build/BuildContext.cs b/build/LocalStack.Build/BuildContext.cs
new file mode 100644
index 0000000..de00584
--- /dev/null
+++ b/build/LocalStack.Build/BuildContext.cs
@@ -0,0 +1,194 @@
+namespace LocalStack.Build;
+
+public sealed class BuildContext : FrostingContext
+{
+ public BuildContext(ICakeContext context) : base(context)
+ {
+ BuildConfiguration = context.Argument("config", "Release");
+ ForceBuild = context.Argument("force-build", false);
+ ForceRestore = context.Argument("force-restore", false);
+ PackageVersion = context.Argument("package-version", "x.x.x");
+ PackageId = context.Argument("package-id", default(string));
+ PackageSecret = context.Argument("package-secret", default(string));
+ PackageSource = context.Argument("package-source", default(string));
+
+ var sourceBuilder = ImmutableDictionary.CreateBuilder();
+ sourceBuilder.AddRange(new[]
+ {
+ new KeyValuePair("myget", "https://www.myget.org/F/localstack-dotnet-client/api/v3/index.json"),
+ new KeyValuePair("nuget", "https://api.nuget.org/v3/index.json")
+ });
+ PackageSourceMap = sourceBuilder.ToImmutable();
+
+ SolutionRoot = context.Directory("../../");
+ SrcPath = SolutionRoot + context.Directory("src");
+ TestsPath = SolutionRoot + context.Directory("tests");
+ BuildPath = SolutionRoot + context.Directory("build");
+ ArtifactOutput = SolutionRoot + context.Directory("artifacts");
+ LocalStackAwsLocalFolder = SrcPath + context.Directory("LocalStack.AwsLocal");
+ SlnFilePath = SolutionRoot + context.File("LocalStack.sln");
+ LocalStackAwsLocalProjFile = LocalStackAwsLocalFolder + context.File("LocalStack.AwsLocal.csproj");
+
+ var packIdBuilder = ImmutableDictionary.CreateBuilder();
+ packIdBuilder.AddRange(new[]
+ {
+ new KeyValuePair("LocalStack.AwsLocal", LocalStackAwsLocalProjFile),
+ });
+ PackageIdProjMap = packIdBuilder.ToImmutable();
+ }
+
+ public string BuildConfiguration { get; }
+
+ public bool ForceBuild { get; }
+
+ public bool ForceRestore { get; }
+
+ public string PackageVersion { get; }
+
+ public string PackageId { get; }
+
+ public string PackageSecret { get; }
+
+ public string PackageSource { get; }
+
+ public ImmutableDictionary PackageSourceMap { get; }
+
+ public ImmutableDictionary PackageIdProjMap { get; }
+
+ public ConvertableFilePath SlnFilePath { get; }
+
+ public ConvertableDirectoryPath SolutionRoot { get; }
+
+ public ConvertableDirectoryPath SrcPath { get; }
+
+ public ConvertableDirectoryPath TestsPath { get; }
+
+ public ConvertableDirectoryPath BuildPath { get; }
+
+ public ConvertableDirectoryPath ArtifactOutput { get; }
+
+ public ConvertableDirectoryPath LocalStackAwsLocalFolder { get; }
+
+ public ConvertableFilePath LocalStackAwsLocalProjFile { get; }
+
+ public static void ValidateArgument(string argumentName, string argument)
+ {
+ if (string.IsNullOrWhiteSpace(argument))
+ {
+ throw new Exception($"{argumentName} can not be null or empty");
+ }
+ }
+
+ public void InstallXUnitNugetPackage()
+ {
+ if (!Directory.Exists("testrunner"))
+ {
+ Directory.CreateDirectory("testrunner");
+ }
+
+ var nugetInstallSettings = new NuGetInstallSettings
+ {
+ Version = "2.4.1",
+ Verbosity = NuGetVerbosity.Normal,
+ OutputDirectory = "testrunner",
+ WorkingDirectory = "."
+ };
+
+ this.NuGetInstall("xunit.runner.console", nugetInstallSettings);
+ }
+
+ public IEnumerable GetProjMetadata()
+ {
+ DirectoryPath testsRoot = this.Directory(TestsPath);
+ List csProjFile = this.GetFiles($"{testsRoot}/**/*.csproj").Where(fp => fp.FullPath.EndsWith("Tests.csproj")).ToList();
+
+ IList projMetadata = new List();
+
+ foreach (FilePath csProj in csProjFile)
+ {
+ string csProjPath = csProj.FullPath;
+
+ IEnumerable targetFrameworks = GetProjectTargetFrameworks(csProjPath);
+ string directoryPath = csProj.GetDirectory().FullPath;
+ string assemblyName = GetAssemblyName(csProjPath);
+
+ var testProjMetadata = new ProjMetadata(directoryPath, csProjPath, targetFrameworks, assemblyName);
+ projMetadata.Add(testProjMetadata);
+ }
+
+ return projMetadata;
+ }
+
+ public void RunXUnitUsingMono(string targetFramework, string assemblyPath)
+ {
+ int exitCode = this.StartProcess("mono", new ProcessSettings
+ {
+ Arguments = $"./testrunner/xunit.runner.console.2.4.1/tools/{targetFramework}/xunit.console.exe {assemblyPath}"
+ });
+
+ if (exitCode != 0)
+ {
+ throw new InvalidOperationException($"Exit code: {exitCode}");
+ }
+ }
+
+ public string GetProjectVersion()
+ {
+ FilePath file = this.File("./src/Directory.Build.props");
+
+ this.Information(file.FullPath);
+
+ string project = File.ReadAllText(file.FullPath, Encoding.UTF8);
+ int startIndex = project.IndexOf("", StringComparison.Ordinal) + "".Length;
+ int endIndex = project.IndexOf("", startIndex, StringComparison.Ordinal);
+
+ string version = project.Substring(startIndex, endIndex - startIndex);
+ version = $"{version}.{PackageVersion}";
+
+ return version;
+ }
+
+ private IEnumerable GetProjectTargetFrameworks(string csprojPath)
+ {
+ FilePath file = this.File(csprojPath);
+ string project = File.ReadAllText(file.FullPath, Encoding.UTF8);
+
+ bool multipleFrameworks = project.Contains("");
+ string startElement = multipleFrameworks ? "" : "";
+ string endElement = multipleFrameworks ? "" : "";
+
+ int startIndex = project.IndexOf(startElement, StringComparison.Ordinal) + startElement.Length;
+ int endIndex = project.IndexOf(endElement, startIndex, StringComparison.Ordinal);
+
+ string targetFrameworks = project.Substring(startIndex, endIndex - startIndex);
+
+ return targetFrameworks.Split(';');
+ }
+
+ private string GetAssemblyName(string csprojPath)
+ {
+ FilePath file = this.File(csprojPath);
+ string project = File.ReadAllText(file.FullPath, Encoding.UTF8);
+
+ bool assemblyNameElementExists = project.Contains("");
+
+ string assemblyName;
+
+ if (assemblyNameElementExists)
+ {
+ int startIndex = project.IndexOf("", StringComparison.Ordinal) + "".Length;
+ int endIndex = project.IndexOf("", startIndex, StringComparison.Ordinal);
+
+ assemblyName = project.Substring(startIndex, endIndex - startIndex);
+ }
+ else
+ {
+ int startIndex = csprojPath.LastIndexOf("/", StringComparison.Ordinal) + 1;
+ int endIndex = csprojPath.IndexOf(".csproj", startIndex, StringComparison.Ordinal);
+
+ assemblyName = csprojPath.Substring(startIndex, endIndex - startIndex);
+ }
+
+ return assemblyName;
+ }
+}
\ No newline at end of file
diff --git a/build/LocalStack.Build/GlobalUsings.cs b/build/LocalStack.Build/GlobalUsings.cs
new file mode 100644
index 0000000..e75d8a2
--- /dev/null
+++ b/build/LocalStack.Build/GlobalUsings.cs
@@ -0,0 +1,22 @@
+global using Cake.Common;
+global using Cake.Common.Diagnostics;
+global using Cake.Common.IO;
+global using Cake.Common.IO.Paths;
+global using Cake.Common.Tools.DotNet.MSBuild;
+global using Cake.Common.Tools.NuGet;
+global using Cake.Common.Tools.NuGet.Install;
+global using Cake.Common.Tools.NuGet.List;
+global using Cake.Core;
+global using Cake.Core.IO;
+global using Cake.Frosting;
+
+global using LocalStack.Build;
+global using LocalStack.Build.Models;
+
+global using System;
+global using System.Collections.Generic;
+global using System.Collections.Immutable;
+global using System.IO;
+global using System.Linq;
+global using System.Text;
+global using System.Text.RegularExpressions;
\ No newline at end of file
diff --git a/build/LocalStack.Build/LocalStack.Build.csproj b/build/LocalStack.Build/LocalStack.Build.csproj
new file mode 100644
index 0000000..95b892f
--- /dev/null
+++ b/build/LocalStack.Build/LocalStack.Build.csproj
@@ -0,0 +1,12 @@
+
+
+ Exe
+ net7.0
+ $(MSBuildProjectDirectory)
+ latest
+ CA1303
+
+
+
+
+
diff --git a/build/LocalStack.Build/Models/ProjMetadata.cs b/build/LocalStack.Build/Models/ProjMetadata.cs
new file mode 100644
index 0000000..27a3dc9
--- /dev/null
+++ b/build/LocalStack.Build/Models/ProjMetadata.cs
@@ -0,0 +1,3 @@
+namespace LocalStack.Build.Models;
+
+public record ProjMetadata(string DirectoryPath, string CsProjPath, IEnumerable TargetFrameworks, string AssemblyName);
\ No newline at end of file
diff --git a/build/LocalStack.Build/Program.cs b/build/LocalStack.Build/Program.cs
new file mode 100644
index 0000000..8cce5dd
--- /dev/null
+++ b/build/LocalStack.Build/Program.cs
@@ -0,0 +1,187 @@
+using Cake.Common.Tools.DotNet;
+using Cake.Common.Tools.DotNet.Build;
+using Cake.Common.Tools.DotNet.NuGet.Push;
+using Cake.Common.Tools.DotNet.Pack;
+using Cake.Common.Tools.DotNet.Test;
+
+return new CakeHost()
+ .UseContext()
+ .Run(args);
+
+[TaskName("Default"), IsDependentOn(typeof(TestTask))]
+public class DefaultTask : FrostingTask
+{
+}
+
+[TaskName("init")]
+public sealed class InitTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ context.StartProcess("dotnet", new ProcessSettings
+ {
+ Arguments = "--info"
+ });
+
+ if (!context.IsRunningOnUnix())
+ {
+ return;
+ }
+
+ context.StartProcess("git", new ProcessSettings
+ {
+ Arguments = "config --global core.autocrlf true"
+ });
+
+ context.StartProcess("mono", new ProcessSettings
+ {
+ Arguments = "--version"
+ });
+
+ context.InstallXUnitNugetPackage();
+ }
+}
+
+[TaskName("build"), IsDependentOn(typeof(InitTask)),]
+public sealed class BuildTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ context.DotNetBuild(context.SlnFilePath,
+ new DotNetBuildSettings
+ {
+ Configuration = context.BuildConfiguration
+ });
+ }
+}
+
+[TaskName("tests"), IsDependentOn(typeof(BuildTask))]
+public sealed class TestTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ const string testResults = "results.trx";
+
+ var settings = new DotNetTestSettings
+ {
+ NoRestore = !context.ForceRestore,
+ NoBuild = !context.ForceBuild,
+ Configuration = context.BuildConfiguration,
+ Blame = true
+ };
+
+ IEnumerable projMetadata = context.GetProjMetadata();
+
+ foreach (ProjMetadata testProj in projMetadata)
+ {
+ string testProjectPath = testProj.CsProjPath;
+ string targetFrameworks = string.Join(",", testProj.TargetFrameworks);
+
+ context.Warning($"Target Frameworks {targetFrameworks}");
+
+ foreach (string targetFramework in testProj.TargetFrameworks)
+ {
+ context.Warning($"=============Running {targetFramework.ToUpper()} tests for {testProj.AssemblyName}=============");
+ settings.Framework = targetFramework;
+
+ if (context.IsRunningOnUnix() && targetFramework == "net461")
+ {
+ context.RunXUnitUsingMono(targetFramework, $"{testProj.DirectoryPath}/bin/{context.BuildConfiguration}/{targetFramework}/{testProj.AssemblyName}.dll");
+ }
+ else
+ {
+ string testFilePrefix = targetFramework.Replace(".", "-");
+ settings.ArgumentCustomization = args => args.Append($" --logger \"trx;LogFileName={testFilePrefix}_{testResults}\"");
+ context.DotNetTest(testProjectPath, settings);
+ }
+ context.Warning("==============================================================");
+ }
+ }
+ }
+}
+
+[TaskName("nuget-pack")]
+public sealed class NugetPackTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ ValidatePackageVersion(context);
+
+ if (!Directory.Exists(context.ArtifactOutput))
+ {
+ Directory.CreateDirectory(context.ArtifactOutput);
+ }
+
+ FilePath packageCsProj = context.PackageIdProjMap[context.PackageId];
+
+ var settings = new DotNetPackSettings
+ {
+ Configuration = context.BuildConfiguration,
+ OutputDirectory = context.ArtifactOutput,
+ MSBuildSettings = new DotNetMSBuildSettings()
+ };
+
+ settings.MSBuildSettings.SetVersion(context.PackageVersion);
+
+ context.DotNetPack(packageCsProj.FullPath, settings);
+ }
+
+ private static void ValidatePackageVersion(BuildContext context)
+ {
+ BuildContext.ValidateArgument("package-id", context.PackageId);
+ BuildContext.ValidateArgument("package-version", context.PackageVersion);
+ BuildContext.ValidateArgument("package-source", context.PackageSource);
+
+ Match match = Regex.Match(context.PackageVersion, @"^(\d+)\.(\d+)\.(\d+)(\.(\d+))*$", RegexOptions.IgnoreCase);
+
+ if (!match.Success)
+ {
+ throw new Exception($"Invalid version: {context.PackageVersion}");
+ }
+
+ string packageSource = context.PackageSourceMap[context.PackageSource];
+
+ var nuGetListSettings = new NuGetListSettings { AllVersions = false, Source = new List() { packageSource } };
+ NuGetListItem nuGetListItem = context.NuGetList(context.PackageId, nuGetListSettings).Single(item => item.Name == context.PackageId);
+ string latestPackVersionStr = nuGetListItem.Version;
+
+ Version packageVersion = Version.Parse(context.PackageVersion);
+ Version latestPackVersion = Version.Parse(latestPackVersionStr);
+
+ if (packageVersion <= latestPackVersion)
+ {
+ throw new Exception($"The new package version {context.PackageVersion} should be greater than the latest package version {latestPackVersionStr}");
+ }
+ }
+}
+
+[TaskName("nuget-push")]
+public sealed class NugetPushTask : FrostingTask
+{
+ public override void Run(BuildContext context)
+ {
+ BuildContext.ValidateArgument("package-id", context.PackageId);
+ BuildContext.ValidateArgument("package-version", context.PackageVersion);
+ BuildContext.ValidateArgument("package-secret", context.PackageSecret);
+ BuildContext.ValidateArgument("package-source", context.PackageSource);
+
+ string packageId = context.PackageId;
+ string packageVersion = context.PackageVersion;
+
+ ConvertableFilePath packageFile = context.ArtifactOutput + context.File($"{packageId}.{packageVersion}.nupkg");
+
+ if (!context.FileExists(packageFile))
+ {
+ throw new Exception($"The specified {packageFile.Path} package file does not exists");
+ }
+
+ string packageSecret = context.PackageSecret;
+ string packageSource = context.PackageSourceMap[context.PackageSource];
+
+ context.DotNetNuGetPush(packageFile.Path.FullPath, new DotNetNuGetPushSettings()
+ {
+ ApiKey = packageSecret,
+ Source = packageSource,
+ });
+ }
+}
\ No newline at end of file
diff --git a/build/LocalStack.Build/Properties/launchSettings-example.json b/build/LocalStack.Build/Properties/launchSettings-example.json
new file mode 100644
index 0000000..e58c2de
--- /dev/null
+++ b/build/LocalStack.Build/Properties/launchSettings-example.json
@@ -0,0 +1,13 @@
+{
+ "profiles": {
+ "LocalStack.Build": {
+ "commandName": "Project",
+ "commandLineArgs": "--target nuget-push --package-version 1.2.3 --package-source myget --package-id LocalStack.Client --package-secret ************************"
+ },
+ "WSL 2": {
+ "commandName": "WSL2",
+ "commandLineArgs": "--target get-version",
+ "distributionName": "Ubuntu-18.04"
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/azure-pipelines.artifact.yml b/build/azure-pipelines.artifact.yml
deleted file mode 100644
index e407fce..0000000
--- a/build/azure-pipelines.artifact.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-trigger:
- branches:
- include:
- - master
- - releases/*
- - feature/*
- paths:
- exclude:
- - README.md
- - CONTRIBUTING.md
- - LICENSE
-pr: none
-pool:
- vmImage: ubuntu-18.04
-variables:
- Version.MajorMinor: 1.3
- Version.Revision: $[counter(variables['Version.MajorMinor'], 0)]
-steps:
- - bash: "sudo apt install nuget && mkdir ./testrunner && sudo chmod -R 777 ./testrunner && ls"
- displayName: "Init Task"
-
- - task: UseDotNet@2
- displayName: ".NET Core 5.0.x"
- inputs:
- version: "5.0.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 3.1.x"
- inputs:
- version: "3.1.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 2.1.x"
- inputs:
- version: "2.1.x"
- packageType: sdk
-
- - task: Bash@3
- displayName: "Compile & Tests"
- inputs:
- targetType: filePath
- filePath: ./build.sh
-
- - bash: echo $(Version.Revision) && chmod +x ./build.sh && sudo ./build.sh --target=get-version --buildnumber=$BUILD_ID
- displayName: "Package Version"
- env:
- BUILD_ID: $(Version.Revision)
-
- - bash: chmod +x ./build.sh && sudo ./build.sh --target=nuget-pack --buildnumber=$BUILD_ID
- displayName: "Nuget Pack"
- env:
- BUILD_ID: $(Version.Revision)
-
- - task: PublishBuildArtifacts@1
- displayName: "Publish Artifact: LocalStack.AwsLocal"
- inputs:
- PathtoPublish: artifacts/
- ArtifactName: LocalStack.AwsLocal
diff --git a/build/azure-pipelines.macos.yml b/build/azure-pipelines.macos.yml
deleted file mode 100644
index 77890c1..0000000
--- a/build/azure-pipelines.macos.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-trigger:
- branches:
- include:
- - "*"
- paths:
- exclude:
- - README.md
- - CONTRIBUTING.md
- - LICENSE
-pr:
- branches:
- include:
- - "*"
-schedules:
- - cron: "0 12 * * 0"
- displayName: Weekly Sunday build
- branches:
- include:
- - master
- always: true
-pool:
- vmImage: macOS-10.14
-steps:
-
- - task: UseDotNet@2
- displayName: ".NET Core 5.0.x"
- inputs:
- version: "5.0.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 3.1.x"
- inputs:
- version: "3.1.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 2.1.x"
- inputs:
- version: "2.1.x"
- packageType: sdk
-
- - task: Bash@3
- displayName: "Compile & Tests"
- inputs:
- targetType: filePath
- filePath: ./build.sh
-
- - task: PublishTestResults@2
- inputs:
- testResultsFormat: "VSTest"
- testResultsFiles: "**/*.trx"
- testRunTitle: "LocalStack.AwsLocal.Tests"
diff --git a/build/azure-pipelines.ubuntu.yml b/build/azure-pipelines.ubuntu.yml
deleted file mode 100644
index 443b5b0..0000000
--- a/build/azure-pipelines.ubuntu.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-trigger:
- branches:
- include:
- - "*"
- paths:
- exclude:
- - README.md
- - CONTRIBUTING.md
- - LICENSE
-pr:
- branches:
- include:
- - "*"
-schedules:
- - cron: "0 12 * * 0"
- displayName: Weekly Sunday build
- branches:
- include:
- - master
- always: true
-pool:
- vmImage: ubuntu-18.04
-steps:
- - bash: "sudo apt install nuget && mkdir ./testrunner && sudo chmod -R 777 ./testrunner && ls"
- displayName: "Init Task"
-
- - task: UseDotNet@2
- displayName: ".NET Core 5.0.x"
- inputs:
- version: "5.0.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 3.1.x"
- inputs:
- version: "3.1.x"
- packageType: sdk
-
- - task: UseDotNet@2
- displayName: ".NET Core 2.1.x"
- inputs:
- version: "2.1.x"
- packageType: sdk
-
- - task: Bash@3
- displayName: "Compile & Tests"
- inputs:
- targetType: filePath
- filePath: ./build.sh
-
- - task: PublishTestResults@2
- inputs:
- testResultsFormat: "VSTest"
- testResultsFiles: "**/*.trx"
- testRunTitle: "LocalStack.AwsLocal.Tests"
diff --git a/build/azure-pipelines.windows.yml b/build/azure-pipelines.windows.yml
deleted file mode 100644
index ed3e721..0000000
--- a/build/azure-pipelines.windows.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-trigger:
- branches:
- include:
- - "*"
- paths:
- exclude:
- - README.md
- - CONTRIBUTING.md
- - LICENSE
-pr:
- branches:
- include:
- - "*"
-schedules:
- - cron: "0 12 * * 0"
- displayName: Weekly Sunday build
- branches:
- include:
- - master
- always: true
-pool:
- vmImage: windows-2019
-steps:
- - checkout: self
- submodules: true
-
- - task: PowerShell@2
- displayName: "Compile & Tests"
- inputs:
- targetType: filePath
- filePath: ./build.ps1
-
- - task: PublishTestResults@2
- inputs:
- testResultsFormat: "VSTest"
- testResultsFiles: "**/*.trx"
- testRunTitle: "LocalStack.AwsLocal.Tests"
diff --git a/build/scripts/packageUpdate.ps1 b/build/scripts/packageUpdate.ps1
new file mode 100644
index 0000000..48318fe
--- /dev/null
+++ b/build/scripts/packageUpdate.ps1
@@ -0,0 +1,17 @@
+$regex = 'PackageReference Include="([^"]*)" Version="([^"]*)"'
+
+ForEach ($file in get-childitem . -recurse | where {$_.extension -like "*proj"})
+{
+ $packages = Get-Content $file.FullName |
+ select-string -pattern $regex -AllMatches |
+ ForEach-Object {$_.Matches} |
+ ForEach-Object {$_.Groups[1].Value.ToString()}|
+ sort -Unique
+
+ ForEach ($package in $packages)
+ {
+ write-host "Update $file package :$package" -foreground 'magenta'
+ $fullName = $file.FullName
+ iex "dotnet add $fullName package $package"
+ }
+}
\ No newline at end of file