diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..831d039b --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "cake.tool": { + "version": "3.0.0", + "commands": [ + "dotnet-cake" + ] + } + } +} \ No newline at end of file diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index b8c18a34..00000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: 1 -update_configs: - - package_manager: "dotnet:nuget" - directory: "/" - update_schedule: "daily" - automerged_updates: - - match: - dependency_name: "ApprovalTests" - update_type: "all" - - match: - dependency_name: "Blorc.*" - update_type: "all" - - match: - dependency_name: "Catel.*" - update_type: "all" - - match: - dependency_name: "Fody" - update_type: "all" - - match: - dependency_name: "*.Fody" - update_type: "all" - - match: - dependency_name: "Microsoft.*" - update_type: "all" - - match: - dependency_name: "NUnit" - update_type: "all" - - match: - dependency_name: "NUnit3TestAdapter" - update_type: "all" - - match: - dependency_name: "Orc.*" - update_type: "all" - - match: - dependency_name: "Orchestra.*" - update_type: "all" - - match: - dependency_name: "PublicApiGenerator" - update_type: "all" - - match: - dependency_name: "Verify.NUnit" - update_type: "all" - ignored_updates: - - match: - dependency_name: "*Analyzers" \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2f946c6a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 +registries: + nuget-feed-default: + type: nuget-feed + url: https://api.nuget.org/v3/index.json + +updates: +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + +- package-ecosystem: nuget + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*Analyzers" + versions: + - ">= 0" + registries: + - nuget-feed-default \ No newline at end of file diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 00000000..c3cf7691 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,40 @@ +name: Dependabot auto-merge +on: pull_request_target +permissions: + pull-requests: write + contents: write +jobs: + dependabot: + runs-on: ubuntu-latest + # Checking the actor will prevent your Action run failing on non-Dependabot PRs + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: dependabot-metadata + uses: dependabot/fetch-metadata@v1.3.6 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: Approve Dependabot PR + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Enable auto-merge for Dependabot PRs + if: | + (startsWith(steps.dependabot-metadata.outputs.dependency-names, 'approvaltests.') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'catel.') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'fody') || + endsWith(steps.dependabot-metadata.outputs.dependency-names, '.fody') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'microsoft.') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'nunit') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'nunit3testadapter') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orc.') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orchestra.') || + startsWith(steps.dependabot-metadata.outputs.dependency-names, 'verify.')) && + (steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor' || + steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch') + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + PR_NUMBER: ${{github.event.pull_request.number}} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 297f1eb9..f9cde13a 100644 --- a/.gitignore +++ b/.gitignore @@ -135,10 +135,17 @@ TestResults .github/ BundleArtifacts/ +# docker / tye +.tye + # editors .idea .vscode +# Binaries +*.dll +*.exe + # fody FodyWeavers.xsd @@ -148,3 +155,7 @@ FodyWeavers.xsd # ANTLR data/dsl/*.class data/dsl/*.java + +# Nodejs / NPM +node_modules +package-lock.json diff --git a/build.cake b/build.cake index c676cc75..cbae0b35 100644 --- a/build.cake +++ b/build.cake @@ -8,11 +8,18 @@ Parameters["SolutionName"] = "Catel.Fody"; Parameters["Company"] = "CatenaLogic"; Parameters["RepositoryUrl"] = string.Format("https://github.com/{0}/{1}", GetBuildServerVariable("SolutionName"), GetBuildServerVariable("SolutionName")); Parameters["StartYear"] = "2010"; -Parameters["UseVisualStudioPrerelease"] = "false"; -Parameters["DeployCatelFodyAttributes"] = "false"; +Parameters["UseVisualStudioPrerelease"] = "true"; + +// Note: Catel.Fody is a special project where the Attributes projects generates +// the correct package with both the attributes *and* the weaver. We should build +// and package Catel.Fody.Attributes, but Catel.Fody is the package that needs to be +// deployed Parameters["BuildCatelFody"] = "true"; -Parameters["DeployCatelFody"] = "false"; -Parameters["DeployCatelFodyAttributes"] = "true"; +Parameters["PackageCatelFody"] = "true"; +Parameters["DeployCatelFody"] = "true"; +Parameters["BuildCatelFodyAttributes"] = "true"; +Parameters["PackageCatelFodyAttributes"] = "true"; +Parameters["DeployCatelFodyAttributes"] = "false"; // Note: the rest of the variables should be coming from the build server, // see `/deployment/cake/*-variables.cake` for customization options @@ -31,8 +38,38 @@ Parameters["DeployCatelFodyAttributes"] = "true"; Components.Add("Catel.Fody"); Components.Add("Catel.Fody.Attributes"); -TestProjects.Add(string.Format("{0}.Tests.Catel5", GetBuildServerVariable("SolutionName"))); -//TestProjects.Add(string.Format("{0}.Tests.Catel6", GetBuildServerVariable("SolutionName"))); +// Components as dependencies since they are required by the test projects +Dependencies.Add("Catel.Fody"); +Dependencies.Add("Catel.Fody.Attributes"); + +Dependencies.Add("Catel.Fody.TestExternalTypesAssembly.Catel5", new [] +{ + "Catel.Fody.Tests.Catel5" +}); +Dependencies.Add("Catel.Fody.TestAssembly.NetStandard.Catel5", new [] +{ + "Catel.Fody.Tests.Catel5" +}); +Dependencies.Add("Catel.Fody.TestAssembly.Catel5", new [] +{ + "Catel.Fody.Tests.Catel5" +}); + +Dependencies.Add("Catel.Fody.TestExternalTypesAssembly.Catel6", new [] +{ + "Catel.Fody.Tests.Catel6" +}); +Dependencies.Add("Catel.Fody.TestAssembly.Catel6", new [] +{ + "Catel.Fody.Tests.Catel6" +}); + +// Test projects as dependencies since they don't following naming convention +Dependencies.Add("Catel.Fody.Tests.Catel5"); +Dependencies.Add("Catel.Fody.Tests.Catel6"); + +TestProjects.Add("Catel.Fody.Tests.Catel5"); +TestProjects.Add("Catel.Fody.Tests.Catel6"); //======================================================= // REQUIRED INITIALIZATION, DO NOT CHANGE diff --git a/build.ps1 b/build.ps1 index 82529cf6..21821d29 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,235 +1,13 @@ -########################################################################## -# This is the Cake bootstrapper script for PowerShell. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## +$ErrorActionPreference = 'Stop' -<# +Set-Location -LiteralPath $PSScriptRoot -.SYNOPSIS -This is a Powershell script to bootstrap a Cake build. +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' +$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' +$env:DOTNET_NOLOGO = '1' -.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. +dotnet tool restore +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -.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 -) - -[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null -function MD5HashFile([string] $filePath) -{ - if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) - { - return $null - } - - [System.IO.Stream] $file = $null; - [System.Security.Cryptography.MD5] $md5 = $null; - try - { - $md5 = [System.Security.Cryptography.MD5]::Create() - $file = [System.IO.File]::OpenRead($filePath) - return [System.BitConverter]::ToString($md5.ComputeHash($file)) - } - finally - { - if ($file -ne $null) - { - $file.Dispose() - } - } -} - -function GetProxyEnabledWebClient -{ - $wc = New-Object System.Net.WebClient - $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials - $wc.Proxy = $proxy - return $wc -} - -Write-Host "Preparing to run build script..." - -if(!$PSScriptRoot){ - $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -} - -$TOOLS_DIR = Join-Path $PSScriptRoot "tools" -$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" -$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" -$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" -$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" -$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" - -# 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 packages.config exist. -if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { - Throw "Could not download packages.config." - } -} - -# Try find NuGet.exe in path if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } - $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 - if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { - Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." - $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName - } -} - -# Try download NuGet.exe if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Downloading NuGet.exe..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile($NUGET_URL, $NUGET_EXE) - } catch { - Throw "Could not download NuGet.exe." - } -} - -# Save nuget.exe path to environment to be available to child processed -$ENV:NUGET_EXE = $NUGET_EXE - -# Restore tools from NuGet? -if(-Not $SkipToolPackageRestore.IsPresent) { - Push-Location - Set-Location $TOOLS_DIR - - # Check for changes in packages.config and remove installed tools if true. - [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) - if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or - ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { - Write-Verbose -Message "Missing or changed package.config hash..." - Get-ChildItem -Exclude packages.config,nuget.exe,Cake.Bakery | - Remove-Item -Recurse - } - - Write-Verbose -Message "Restoring tools from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet tools." - } - else - { - $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" - } - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore addins from NuGet -if (Test-Path $ADDINS_PACKAGES_CONFIG) { - Push-Location - Set-Location $ADDINS_DIR - - Write-Verbose -Message "Restoring addins from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet addins." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore modules from NuGet -if (Test-Path $MODULES_PACKAGES_CONFIG) { - Push-Location - Set-Location $MODULES_DIR - - Write-Verbose -Message "Restoring modules from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occurred while restoring NuGet modules." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe 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..." -&$CAKE_EXE $cakeArguments -exit $LASTEXITCODE +dotnet cake @args +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/cake.config b/cake.config index 979dba96..26d2a8a7 100644 --- a/cake.config +++ b/cake.config @@ -1,4 +1,11 @@ ; The configuration file for Cake. [Settings] -SkipVerification=true \ No newline at end of file +SkipVerification=true + +[Settings] +EnableScriptCache=true + +[Paths] +; Cache=%temp%/cake-build/cache/ +; Note: cache-path is set via environment variables \ No newline at end of file diff --git a/deployment/cake/apps-uwp-tasks.cake b/deployment/cake/apps-uwp-tasks.cake index cb91971f..43ce6221 100644 --- a/deployment/cake/apps-uwp-tasks.cake +++ b/deployment/cake/apps-uwp-tasks.cake @@ -126,7 +126,7 @@ public class UwpProcessor : ProcessorBase PlatformTarget = platform.Value }; - ConfigureMsBuild(BuildContext, msBuildSettings, uwpApp); + ConfigureMsBuild(BuildContext, msBuildSettings, uwpApp, "build"); // Always disable SourceLink msBuildSettings.WithProperty("EnableSourceLink", "false"); @@ -145,7 +145,7 @@ public class UwpProcessor : ProcessorBase // Note: if csproj doesn't work, use SolutionFileName instead //var projectFileName = SolutionFileName; - RunMsBuild(BuildContext, uwpApp, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, uwpApp, projectFileName, msBuildSettings, "build"); // Recalculate! appxUploadFileName = GetAppxUploadFileName(artifactsDirectory, uwpApp, BuildContext.General.Version.MajorMinorPatch); diff --git a/deployment/cake/apps-web-tasks.cake b/deployment/cake/apps-web-tasks.cake index fca37432..cd548512 100644 --- a/deployment/cake/apps-web-tasks.cake +++ b/deployment/cake/apps-web-tasks.cake @@ -79,23 +79,12 @@ public class WebProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, webApp); + ConfigureMsBuild(BuildContext, msBuildSettings, webApp, "build"); // Always disable SourceLink msBuildSettings.WithProperty("EnableSourceLink", "false"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, webApp); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); - - // TODO: Enable GitLink / SourceLink, see RepositoryUrl, RepositoryBranchName, RepositoryCommitId variables - - RunMsBuild(BuildContext, webApp, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, webApp, projectFileName, msBuildSettings, "build"); } } @@ -110,9 +99,9 @@ public class WebProcessor : ProcessorBase foreach (var webApp in BuildContext.Web.Items) { - if (!ShouldDeployProject(BuildContext, webApp)) + if (!ShouldPackageProject(BuildContext, webApp)) { - CakeContext.Information("Web app '{0}' should not be deployed", webApp); + CakeContext.Information("Web app '{0}' should not be packaged", webApp); continue; } @@ -125,34 +114,29 @@ public class WebProcessor : ProcessorBase CakeContext.Information("1) Using 'dotnet publish' to package '{0}'", webApp); - var msBuildSettings = new DotNetCoreMSBuildSettings(); + var msBuildSettings = new DotNetMSBuildSettings(); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); msBuildSettings.WithProperty("PackageOutputPath", outputDirectory); msBuildSettings.WithProperty("ConfigurationName", BuildContext.General.Solution.ConfigurationName); msBuildSettings.WithProperty("PackageVersion", BuildContext.General.Version.NuGet); - var publishSettings = new DotNetCorePublishSettings + var publishSettings = new DotNetPublishSettings { MSBuildSettings = msBuildSettings, OutputDirectory = outputDirectory, Configuration = BuildContext.General.Solution.ConfigurationName }; - CakeContext.DotNetCorePublish(projectFileName, publishSettings); + CakeContext.DotNetPublish(projectFileName, publishSettings); CakeContext.Information("2) Using 'octo pack' to package '{0}'", webApp); - var toolSettings = new DotNetCoreToolSettings + var toolSettings = new DotNetToolSettings { }; var octoPackCommand = string.Format("--id {0} --version {1} --basePath {0}", webApp, BuildContext.General.Version.NuGet); - CakeContext.DotNetCoreTool(outputDirectory, "octo pack", octoPackCommand, toolSettings); + CakeContext.DotNetTool(outputDirectory, "octo pack", octoPackCommand, toolSettings); BuildContext.CakeContext.LogSeparator(); } diff --git a/deployment/cake/apps-wpf-tasks.cake b/deployment/cake/apps-wpf-tasks.cake index d89897e4..44ea8a45 100644 --- a/deployment/cake/apps-wpf-tasks.cake +++ b/deployment/cake/apps-wpf-tasks.cake @@ -79,21 +79,12 @@ public class WpfProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, wpfApp); + ConfigureMsBuild(BuildContext, msBuildSettings, wpfApp, "build"); // Always disable SourceLink msBuildSettings.WithProperty("EnableSourceLink", "false"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = GetProjectOutputDirectory(BuildContext, wpfApp); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); - - RunMsBuild(BuildContext, wpfApp, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, wpfApp, projectFileName, msBuildSettings, "build"); } } @@ -137,9 +128,9 @@ public class WpfProcessor : ProcessorBase foreach (var wpfApp in BuildContext.Wpf.Items) { - if (!ShouldDeployProject(BuildContext, wpfApp)) + if (!ShouldPackageProject(BuildContext, wpfApp)) { - CakeContext.Information($"WPF app '{wpfApp}' should not be deployed"); + CakeContext.Information($"WPF app '{wpfApp}' should not be packaged"); continue; } @@ -179,8 +170,8 @@ public class WpfProcessor : ProcessorBase BuildContext.CakeContext.Information($" - {dllSignFilesSearchPattern}"); projectFilesToSign.AddRange(BuildContext.CakeContext.GetFiles(dllSignFilesSearchPattern)); - var signToolCommand = string.Format("sign /a /t {0} /n {1}", BuildContext.General.CodeSign.TimeStampUri, - BuildContext.General.CodeSign.CertificateSubjectName); + var signToolCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", BuildContext.General.CodeSign.TimeStampUri, + BuildContext.General.CodeSign.CertificateSubjectName, BuildContext.General.CodeSign.HashAlgorithm); SignFiles(BuildContext, signToolCommand, projectFilesToSign); } @@ -232,6 +223,15 @@ public class WpfProcessor : ProcessorBase BuildContext.CakeContext.LogSeparator($"Deploying WPF app '{wpfApp}'"); + // TODO: Respect the deploy settings per category, requires changes to AzureStorageSync + if (!BuildContext.Wpf.DeployUpdatesToAlphaChannel || + !BuildContext.Wpf.DeployUpdatesToBetaChannel || + !BuildContext.Wpf.DeployUpdatesToStableChannel || + !BuildContext.Wpf.DeployInstallers) + { + throw new Exception("Not deploying a specific channel is not yet supported, please implement"); + } + //%DeploymentsShare%\%ProjectName% /%ProjectName% -c %AzureDeploymentsStorageConnectionString% var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(wpfApp); var projectSlug = GetProjectSlug(wpfApp, "-"); diff --git a/deployment/cake/apps-wpf-variables.cake b/deployment/cake/apps-wpf-variables.cake index 4a3385a4..6e8356c3 100644 --- a/deployment/cake/apps-wpf-variables.cake +++ b/deployment/cake/apps-wpf-variables.cake @@ -16,6 +16,13 @@ public class WpfContext : BuildContextWithItemsBase public bool UpdateDeploymentsShare { get; set; } public string AzureDeploymentsStorageConnectionString { get; set; } + public bool GenerateDeploymentCatalog { get; set; } + public bool GroupUpdatesByMajorVersion { get; set; } + public bool DeployUpdatesToAlphaChannel { get; set; } + public bool DeployUpdatesToBetaChannel { get; set; } + public bool DeployUpdatesToStableChannel { get; set; } + public bool DeployInstallers { get; set; } + protected override void ValidateContext() { @@ -24,6 +31,13 @@ public class WpfContext : BuildContextWithItemsBase protected override void LogStateInfoForContext() { CakeContext.Information($"Found '{Items.Count}' wpf projects"); + + CakeContext.Information($"Generate Deployment Catalog: '{GenerateDeploymentCatalog}'"); + CakeContext.Information($"Group updates by major version: '{GroupUpdatesByMajorVersion}'"); + CakeContext.Information($"Deploy updates to alpha channel: '{DeployUpdatesToAlphaChannel}'"); + CakeContext.Information($"Deploy updates to beta channel: '{DeployUpdatesToBetaChannel}'"); + CakeContext.Information($"Deploy updates to stable channel: '{DeployUpdatesToStableChannel}'"); + CakeContext.Information($"Deploy installers: '{DeployInstallers}'"); } public string GetDeploymentShareForProject(string projectName) @@ -46,7 +60,13 @@ private WpfContext InitializeWpfContext(BuildContext buildContext, IBuildContext Channel = buildContext.BuildServer.GetVariable("Channel", showValue: true), AppendDeploymentChannelSuffix = buildContext.BuildServer.GetVariableAsBool("AppendDeploymentChannelSuffix", false, showValue: true), UpdateDeploymentsShare = buildContext.BuildServer.GetVariableAsBool("UpdateDeploymentsShare", true, showValue: true), - AzureDeploymentsStorageConnectionString = buildContext.BuildServer.GetVariable("AzureDeploymentsStorageConnectionString") + AzureDeploymentsStorageConnectionString = buildContext.BuildServer.GetVariable("AzureDeploymentsStorageConnectionString"), + GenerateDeploymentCatalog = buildContext.BuildServer.GetVariableAsBool("WpfGenerateDeploymentCatalog", true, showValue: true), + GroupUpdatesByMajorVersion = buildContext.BuildServer.GetVariableAsBool("WpfGroupUpdatesByMajorVersion", false, showValue: true), + DeployUpdatesToAlphaChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToAlphaChannel", true, showValue: true), + DeployUpdatesToBetaChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToBetaChannel", true, showValue: true), + DeployUpdatesToStableChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToStableChannel", true, showValue: true), + DeployInstallers = buildContext.BuildServer.GetVariableAsBool("WpfDeployInstallers", true, showValue: true), }; if (string.IsNullOrWhiteSpace(data.Channel)) diff --git a/deployment/cake/buildserver-continuaci.cake b/deployment/cake/buildserver-continuaci.cake index 5af1e51a..44d390f8 100644 --- a/deployment/cake/buildserver-continuaci.cake +++ b/deployment/cake/buildserver-continuaci.cake @@ -1,13 +1,99 @@ -public class ContinuaCIBuildServer : IBuildServer +public class ContinuaCIBuildServer : BuildServerBase { public ContinuaCIBuildServer(ICakeContext cakeContext) + : base(cakeContext) { - CakeContext = cakeContext; } - public ICakeContext CakeContext { get; private set; } + //------------------------------------------------------------- + + public override async Task OnTestFailedAsync() + { + await ImportUnitTestsAsync(); + } + + //------------------------------------------------------------- + + public override async Task AfterTestAsync() + { + await ImportUnitTestsAsync(); + } + + //------------------------------------------------------------- + + private async Task ImportUnitTestsAsync() + { + foreach (var project in BuildContext.Tests.Items) + { + await ImportTestFilesAsync(project); + } + } + + //------------------------------------------------------------- + + private async Task ImportTestFilesAsync(string projectName) + { + var continuaCIContext = GetContinuaCIContext(); + if (!continuaCIContext.IsRunningOnContinuaCI) + { + return; + } + + CakeContext.Warning($"Importing test results for '{projectName}'"); + + var testResultsDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "testresults"); + + if (!CakeContext.DirectoryExists(testResultsDirectory)) + { + CakeContext.Warning("No test results directory"); + return; + } + + var type = string.Empty; + var importType = string.Empty; - public void PinBuild(string comment) + if (IsNUnitTestProject(BuildContext, projectName)) + { + type = "nunit"; + importType = "nunit"; + } + + if (IsXUnitTestProject(BuildContext, projectName)) + { + type = "xunit"; + importType = "mstest"; // Xml type is different + } + + if (string.IsNullOrWhiteSpace(type)) + { + CakeContext.Warning("Could not find test project type"); + return; + } + + CakeContext.Warning($"Determined project type '{type}'"); + + var cakeFilePattern = System.IO.Path.Combine(testResultsDirectory, projectName, "*.xml"); + + CakeContext.Warning($"Using pattern '{cakeFilePattern}'"); + + var testResultsFiles = CakeContext.GetFiles(cakeFilePattern); + if (!testResultsFiles.Any()) + { + CakeContext.Warning($"No test result file found using '{cakeFilePattern}'"); + return; + } + + var continuaCiFilePattern = System.IO.Path.Combine(testResultsDirectory, "**.xml"); + + CakeContext.Information($"Importing test results from using '{continuaCiFilePattern}' using import type '{importType}'"); + + var message = $"@@continua[importUnitTestResults type='{importType}' filePatterns='{cakeFilePattern}']"; + WriteIntegration(message); + } + + //------------------------------------------------------------- + + public override async Task PinBuildAsync(string comment) { var continuaCIContext = GetContinuaCIContext(); if (!continuaCIContext.IsRunningOnContinuaCI) @@ -22,7 +108,9 @@ public class ContinuaCIBuildServer : IBuildServer WriteIntegration(message); } - public void SetVersion(string version) + //------------------------------------------------------------- + + public override async Task SetVersionAsync(string version) { var continuaCIContext = GetContinuaCIContext(); if (!continuaCIContext.IsRunningOnContinuaCI) @@ -36,7 +124,9 @@ public class ContinuaCIBuildServer : IBuildServer WriteIntegration(message); } - public void SetVariable(string variableName, string value) + //------------------------------------------------------------- + + public override async Task SetVariableAsync(string variableName, string value) { var continuaCIContext = GetContinuaCIContext(); if (!continuaCIContext.IsRunningOnContinuaCI) @@ -50,7 +140,9 @@ public class ContinuaCIBuildServer : IBuildServer WriteIntegration(message); } - public Tuple GetVariable(string variableName, string defaultValue) + //------------------------------------------------------------- + + public override Tuple GetVariable(string variableName, string defaultValue) { var continuaCIContext = GetContinuaCIContext(); if (!continuaCIContext.IsRunningOnContinuaCI) @@ -73,11 +165,15 @@ public class ContinuaCIBuildServer : IBuildServer return new Tuple(exists, value); } + //------------------------------------------------------------- + private IContinuaCIProvider GetContinuaCIContext() { return CakeContext.ContinuaCI(); } + //------------------------------------------------------------- + private void WriteIntegration(string message) { // Must be Console.WriteLine diff --git a/deployment/cake/buildserver.cake b/deployment/cake/buildserver.cake index 6d6837b3..053d710e 100644 --- a/deployment/cake/buildserver.cake +++ b/deployment/cake/buildserver.cake @@ -5,10 +5,150 @@ using System.Runtime.InteropServices; public interface IBuildServer { - void PinBuild(string comment); - void SetVersion(string version); - void SetVariable(string name, string value); + Task PinBuildAsync(string comment); + Task SetVersionAsync(string version); + Task SetVariableAsync(string name, string value); Tuple GetVariable(string variableName, string defaultValue); + + void SetBuildContext(BuildContext buildContext); + + Task BeforeInitializeAsync(); + Task AfterInitializeAsync(); + + Task BeforePrepareAsync(); + Task AfterPrepareAsync(); + + Task BeforeUpdateInfoAsync(); + Task AfterUpdateInfoAsync(); + + Task BeforeBuildAsync(); + Task OnBuildFailedAsync(); + Task AfterBuildAsync(); + + Task BeforeTestAsync(); + Task OnTestFailedAsync(); + Task AfterTestAsync(); + + Task BeforePackageAsync(); + Task AfterPackageAsync(); + + Task BeforeDeployAsync(); + Task AfterDeployAsync(); + + Task BeforeFinalizeAsync(); + Task AfterFinalizeAsync(); +} + +public abstract class BuildServerBase : IBuildServer +{ + protected BuildServerBase(ICakeContext cakeContext) + { + CakeContext = cakeContext; + } + + public ICakeContext CakeContext { get; private set; } + + public BuildContext BuildContext { get; private set; } + + public abstract Task PinBuildAsync(string comment); + public abstract Task SetVersionAsync(string version); + public abstract Task SetVariableAsync(string name, string value); + public abstract Tuple GetVariable(string variableName, string defaultValue); + + //------------------------------------------------------------- + + public void SetBuildContext(BuildContext buildContext) + { + BuildContext = buildContext; + } + + //------------------------------------------------------------- + + public virtual async Task BeforeInitializeAsync() + { + } + + public virtual async Task AfterInitializeAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforePrepareAsync() + { + } + + public virtual async Task AfterPrepareAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforeUpdateInfoAsync() + { + } + + public virtual async Task AfterUpdateInfoAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforeBuildAsync() + { + } + + public virtual async Task OnBuildFailedAsync() + { + } + + public virtual async Task AfterBuildAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforeTestAsync() + { + } + + public virtual async Task OnTestFailedAsync() + { + } + + public virtual async Task AfterTestAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforePackageAsync() + { + } + + public virtual async Task AfterPackageAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforeDeployAsync() + { + } + + public virtual async Task AfterDeployAsync() + { + } + + //------------------------------------------------------------- + + public virtual async Task BeforeFinalizeAsync() + { + } + + public virtual async Task AfterFinalizeAsync() + { + } } //------------------------------------------------------------- @@ -28,7 +168,6 @@ public class BuildServerIntegration : IIntegration private readonly List _buildServers = new List(); private readonly Dictionary _buildServerVariableCache = new Dictionary(); - // This is a special integration that only gets ICakeContext, not the BuildContext public BuildServerIntegration(ICakeContext cakeContext, Dictionary parameters) { CakeContext = cakeContext; @@ -37,33 +176,207 @@ public class BuildServerIntegration : IIntegration _buildServers.Add(new ContinuaCIBuildServer(cakeContext)); } + public void SetBuildContext(BuildContext buildContext) + { + BuildContext = buildContext; + + foreach (var buildServer in _buildServers) + { + buildServer.SetBuildContext(buildContext); + } + } + + public BuildContext BuildContext { get; private set; } + public ICakeContext CakeContext { get; private set; } - public void PinBuild(string comment) + //------------------------------------------------------------- + + public async Task BeforeInitializeAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeInitializeAsync(); + } + } + + public async Task AfterInitializeAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterInitializeAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforePrepareAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforePrepareAsync(); + } + } + + public async Task AfterPrepareAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterPrepareAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforeUpdateInfoAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeUpdateInfoAsync(); + } + } + + public async Task AfterUpdateInfoAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterUpdateInfoAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforeBuildAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeBuildAsync(); + } + } + + public async Task OnBuildFailedAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.OnBuildFailedAsync(); + } + } + + public async Task AfterBuildAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterBuildAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforeTestAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeTestAsync(); + } + } + + public async Task OnTestFailedAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.OnTestFailedAsync(); + } + } + + public async Task AfterTestAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterTestAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforePackageAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforePackageAsync(); + } + } + + public async Task AfterPackageAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterPackageAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforeDeployAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeDeployAsync(); + } + } + + public async Task AfterDeployAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterDeployAsync(); + } + } + + //------------------------------------------------------------- + + public async Task BeforeFinalizeAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.BeforeFinalizeAsync(); + } + } + + public async Task AfterFinalizeAsync() + { + foreach (var buildServer in _buildServers) + { + await buildServer.AfterFinalizeAsync(); + } + } + + //------------------------------------------------------------- + + public async Task PinBuildAsync(string comment) { foreach (var buildServer in _buildServers) { - buildServer.PinBuild(comment); + await buildServer.PinBuildAsync(comment); } } //------------------------------------------------------------- - public void SetVersion(string version) + public async Task SetVersionAsync(string version) { foreach (var buildServer in _buildServers) { - buildServer.SetVersion(version); + await buildServer.SetVersionAsync(version); } } //------------------------------------------------------------- - public void SetVariable(string variableName, string value) + public async Task SetVariableAsync(string variableName, string value) { foreach (var buildServer in _buildServers) { - buildServer.SetVariable(variableName, value); + await buildServer.SetVariableAsync(variableName, value); } } diff --git a/deployment/cake/codesigning-tasks.cake b/deployment/cake/codesigning-tasks.cake new file mode 100644 index 00000000..be849dde --- /dev/null +++ b/deployment/cake/codesigning-tasks.cake @@ -0,0 +1,7 @@ +#l "codesigning-variables.cake" + +using System.Xml.Linq; + +//------------------------------------------------------------- + +// Empty by design for now diff --git a/deployment/cake/codesigning-variables.cake b/deployment/cake/codesigning-variables.cake new file mode 100644 index 00000000..eefb4444 --- /dev/null +++ b/deployment/cake/codesigning-variables.cake @@ -0,0 +1,52 @@ +#l "buildserver.cake" + +//------------------------------------------------------------- + +public class CodeSigningContext : BuildContextBase +{ + public CodeSigningContext(IBuildContext parentBuildContext) + : base(parentBuildContext) + { + } + + public List ProjectsToSignImmediately { get; set; } + + protected override void ValidateContext() + { + + } + + protected override void LogStateInfoForContext() + { + //CakeContext.Information($"Found '{Items.Count}' component projects"); + } +} + +//------------------------------------------------------------- + +private CodeSigningContext InitializeCodeSigningContext(BuildContext buildContext, IBuildContext parentBuildContext) +{ + var data = new CodeSigningContext(parentBuildContext) + { + ProjectsToSignImmediately = CodeSignImmediately ?? new List(), + }; + + return data; +} + +//------------------------------------------------------------- + +List _codeSignImmediately; + +public List CodeSignImmediately +{ + get + { + if (_codeSignImmediately is null) + { + _codeSignImmediately = new List(); + } + + return _codeSignImmediately; + } +} \ No newline at end of file diff --git a/deployment/cake/components-tasks.cake b/deployment/cake/components-tasks.cake index 50c7e593..cf543969 100644 --- a/deployment/cake/components-tasks.cake +++ b/deployment/cake/components-tasks.cake @@ -123,19 +123,17 @@ public class ComponentsProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, component); + ConfigureMsBuild(BuildContext, msBuildSettings, component, "build"); // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) var outputDirectory = GetProjectOutputDirectory(BuildContext, component); CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); // SourceLink specific stuff - if (IsSourceLinkSupported(BuildContext, projectFileName)) + if (IsSourceLinkSupported(BuildContext, component, projectFileName)) { var repositoryUrl = BuildContext.General.Repository.Url; var repositoryCommitId = BuildContext.General.Repository.CommitId; @@ -152,10 +150,10 @@ public class ComponentsProcessor : ProcessorBase msBuildSettings.WithProperty("RepositoryUrl", repositoryUrl); msBuildSettings.WithProperty("RevisionId", repositoryCommitId); - InjectSourceLinkInProjectFile(BuildContext, projectFileName); + InjectSourceLinkInProjectFile(BuildContext, component, projectFileName); } - RunMsBuild(BuildContext, component, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, component, projectFileName, msBuildSettings, "build"); } } @@ -173,12 +171,15 @@ public class ComponentsProcessor : ProcessorBase // Note: some projects, such as Catel.Fody, require packaging // of non-deployable projects if (BuildContext.General.SkipComponentsThatAreNotDeployable && - !ShouldDeployProject(BuildContext, component)) + !ShouldPackageProject(BuildContext, component)) { - CakeContext.Information("Component '{0}' should not be deployed", component); + CakeContext.Information("Component '{0}' should not be packaged", component); continue; } + // Special exception for Blazor projects + var isBlazorProject = IsBlazorProject(BuildContext, component); + BuildContext.CakeContext.LogSeparator("Packaging component '{0}'", component); var projectDirectory = GetProjectDirectory(component); @@ -199,19 +200,23 @@ public class ComponentsProcessor : ProcessorBase var binFiles = CakeContext.GetFiles(binFolderPattern); CakeContext.DeleteFiles(binFiles); - var objFolderPattern = string.Format("{0}/obj/{1}/**.dll", projectDirectory, configurationName); + if (!isBlazorProject) + { + var objFolderPattern = string.Format("{0}/obj/{1}/**.dll", projectDirectory, configurationName); - CakeContext.Information("Deleting 'bin' directory contents using '{0}'", objFolderPattern); + CakeContext.Information("Deleting 'bin' directory contents using '{0}'", objFolderPattern); - var objFiles = CakeContext.GetFiles(objFolderPattern); - CakeContext.DeleteFiles(objFiles); + var objFiles = CakeContext.GetFiles(objFolderPattern); + CakeContext.DeleteFiles(objFiles); + } CakeContext.Information(string.Empty); // Step 2: Go packaging! CakeContext.Information("Using 'msbuild' to package '{0}'", component); - var msBuildSettings = new MSBuildSettings { + var msBuildSettings = new MSBuildSettings + { Verbosity = Verbosity.Quiet, //Verbosity = Verbosity.Diagnostic, ToolVersion = MSBuildToolVersion.Default, @@ -225,9 +230,7 @@ public class ComponentsProcessor : ProcessorBase // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which // are properties passed in using the command line) - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("ConfigurationName", configurationName); msBuildSettings.WithProperty("PackageVersion", BuildContext.General.Version.NuGet); @@ -254,11 +257,35 @@ public class ComponentsProcessor : ProcessorBase // Fix for .NET Core 3.0, see https://github.com/dotnet/core-sdk/issues/192, it // uses obj/release instead of [outputdirectory] msBuildSettings.WithProperty("DotNetPackIntermediateOutputPath", outputDirectory); - - msBuildSettings.WithProperty("NoBuild", "true"); + + var noBuild = true; + + if (isBlazorProject) + { + CakeContext.Information("Allowing build and package restore during package phase since this is a Blazor project which requires the 'obj' directory"); + + // Don't use WithProperty since that will concatenate, and we need to overwrite the + // value here + //msBuildSettings.WithProperty("ResolveNuGetPackages", "true"); + msBuildSettings.Properties["ResolveNuGetPackages"] = new List + { + "true" + }; + + msBuildSettings.Restore = true; + noBuild = false; + } + + // As described in the this issue: https://github.com/NuGet/Home/issues/4360 + // we should not use IsTool, but set BuildOutputTargetFolder instead + msBuildSettings.WithProperty("CopyLocalLockFileAssemblies", "true"); + msBuildSettings.WithProperty("IncludeBuildOutput", "true"); + msBuildSettings.WithProperty("NoDefaultExcludes", "true"); + + msBuildSettings.WithProperty("NoBuild", noBuild.ToString()); msBuildSettings.Targets.Add("Pack"); - RunMsBuild(BuildContext, component, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, component, projectFileName, msBuildSettings, "pack"); BuildContext.CakeContext.LogSeparator(); } diff --git a/deployment/cake/dependencies-tasks.cake b/deployment/cake/dependencies-tasks.cake index 5b591f3a..b624b09b 100644 --- a/deployment/cake/dependencies-tasks.cake +++ b/deployment/cake/dependencies-tasks.cake @@ -19,20 +19,50 @@ public class DependenciesProcessor : ProcessorBase public override async Task PrepareAsync() { + BuildContext.CakeContext.Information($"Checking '{BuildContext.Dependencies.Items.Count}' dependencies"); + if (!HasItems()) { return; } + // We need to go through this twice because a dependency can be a dependency of a dependency + var dependenciesToBuild = new List(); + // Check whether projects should be processed, `.ToList()` // is required to prevent issues with foreach + for (int i = 0; i < 3; i++) + { + foreach (var dependency in BuildContext.Dependencies.Items.ToList()) + { + if (dependenciesToBuild.Contains(dependency)) + { + // Already done + continue; + } + + BuildContext.CakeContext.Information($"Checking dependency '{dependency}' using run {i + 1}"); + + if (BuildContext.Dependencies.ShouldBuildDependency(dependency, dependenciesToBuild)) + { + BuildContext.CakeContext.Information($"Dependency '{dependency}' should be included"); + + dependenciesToBuild.Add(dependency); + } + } + } + + // TODO: How to determine the sort order? E.g. dependencies of dependencies? + foreach (var dependency in BuildContext.Dependencies.Items.ToList()) { - // Note: dependencies should always be built - // if (!ShouldProcessProject(BuildContext, dependency)) - // { - // BuildContext.Dependencies.Items.Remove(dependency); - // } + if (!dependenciesToBuild.Contains(dependency)) + { + BuildContext.CakeContext.Information($"Skipping dependency '{dependency}' because no dependent projects are included"); + + BuildContext.Dependencies.Dependencies.Remove(dependency); + BuildContext.Dependencies.Items.Remove(dependency); + } } } @@ -64,7 +94,7 @@ public class DependenciesProcessor : ProcessorBase } foreach (var dependency in BuildContext.Dependencies.Items) - { + { BuildContext.CakeContext.LogSeparator("Building dependency '{0}'", dependency); var projectFileName = GetProjectFileName(BuildContext, dependency); @@ -79,7 +109,7 @@ public class DependenciesProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, dependency); + ConfigureMsBuild(BuildContext, msBuildSettings, dependency, "build"); // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which @@ -92,14 +122,8 @@ public class DependenciesProcessor : ProcessorBase msBuildSettings.PlatformTarget = PlatformTarget.Win32; } - var outputDirectory = GetProjectOutputDirectory(BuildContext, dependency); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); - // SourceLink specific stuff - if (IsSourceLinkSupported(BuildContext, projectFileName)) + if (IsSourceLinkSupported(BuildContext, dependency, projectFileName)) { var repositoryUrl = BuildContext.General.Repository.Url; var repositoryCommitId = BuildContext.General.Repository.CommitId; @@ -116,10 +140,29 @@ public class DependenciesProcessor : ProcessorBase msBuildSettings.WithProperty("RepositoryUrl", repositoryUrl); msBuildSettings.WithProperty("RevisionId", repositoryCommitId); - InjectSourceLinkInProjectFile(BuildContext, projectFileName); + InjectSourceLinkInProjectFile(BuildContext, dependency, projectFileName); + } + + // Specific code signing, requires the following MSBuild properties: + // * CodeSignEnabled + // * CodeSignCommand + // + // This feature is built to allow projects that have post-build copy + // steps (e.g. for assets) to be signed correctly before being embedded + if (ShouldSignImmediately(BuildContext, dependency)) + { + var codeSignToolFileName = FindSignToolFileName(BuildContext); + var codeSignVerifyCommand = $"verify /pa"; + var codeSignCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", BuildContext.General.CodeSign.TimeStampUri, + BuildContext.General.CodeSign.CertificateSubjectName, BuildContext.General.CodeSign.HashAlgorithm); + + msBuildSettings.WithProperty("CodeSignToolFileName", codeSignToolFileName); + msBuildSettings.WithProperty("CodeSignVerifyCommand", codeSignVerifyCommand); + msBuildSettings.WithProperty("CodeSignCommand", codeSignCommand); + msBuildSettings.WithProperty("CodeSignEnabled", "true"); } - RunMsBuild(BuildContext, dependency, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, dependency, projectFileName, msBuildSettings, "build"); } } diff --git a/deployment/cake/dependencies-variables.cake b/deployment/cake/dependencies-variables.cake index 2dd7072d..b6335d86 100644 --- a/deployment/cake/dependencies-variables.cake +++ b/deployment/cake/dependencies-variables.cake @@ -4,11 +4,15 @@ public class DependenciesContext : BuildContextWithItemsBase { - public DependenciesContext(IBuildContext parentBuildContext) + public DependenciesContext(IBuildContext parentBuildContext, Dictionary> dependencies) : base(parentBuildContext) { + Dependencies = dependencies ?? new Dictionary>(); + Items = Dependencies.Keys.ToList(); } + public Dictionary> Dependencies { get; private set; } + protected override void ValidateContext() { @@ -18,31 +22,80 @@ public class DependenciesContext : BuildContextWithItemsBase { CakeContext.Information($"Found '{Items.Count}' dependency projects"); } + + public bool ShouldBuildDependency(string dependencyProject) + { + return ShouldBuildDependency(dependencyProject, Array.Empty()); + } + + public bool ShouldBuildDependency(string dependencyProject, IEnumerable knownDependenciesToBeBuilt) + { + if (!Dependencies.TryGetValue(dependencyProject, out var dependencyInfo)) + { + return false; + } + + if (dependencyInfo.Count == 0) + { + // No explicit projects defined, always build dependency + return true; + } + + foreach (var projectRequiringDependency in dependencyInfo) + { + CakeContext.Information($"Checking whether '{projectRequiringDependency}' is in the list to be processed"); + + // Check dependencies of dependencies + if (knownDependenciesToBeBuilt.Any(x => string.Equals(x, projectRequiringDependency, StringComparison.OrdinalIgnoreCase))) + { + CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of dependency project '{projectRequiringDependency}', including this in the build"); + return true; + } + + // Special case: *if* this is the 2nd round we check, and the project requiring this dependency is a test project, + // we should check whether the test project is not already excluded. If so, the Deploy[SomeProject]Tests will return true + // and this logic will still include it, so we need to exclude it explicitly + if (IsTestProject((BuildContext)ParentContext, projectRequiringDependency) && + !knownDependenciesToBeBuilt.Contains(projectRequiringDependency)) + { + CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of '{projectRequiringDependency}', but that is an already excluded test project, not yet including in the build"); + + // Important: don't return, there might be other projects + continue; + } + + // Check if we should build this project + if (ShouldProcessProject((BuildContext)ParentContext, projectRequiringDependency)) + { + CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of '{projectRequiringDependency}', including this in the build"); + return true; + } + } + + return false; + } } //------------------------------------------------------------- private DependenciesContext InitializeDependenciesContext(BuildContext buildContext, IBuildContext parentBuildContext) { - var data = new DependenciesContext(parentBuildContext) - { - Items = Dependencies ?? new List() - }; + var data = new DependenciesContext(parentBuildContext, Dependencies); return data; } //------------------------------------------------------------- -List _dependencies; +Dictionary> _dependencies; -public List Dependencies +public Dictionary> Dependencies { get { if (_dependencies is null) { - _dependencies = new List(); + _dependencies = new Dictionary>(); } return _dependencies; diff --git a/deployment/cake/docker-tasks.cake b/deployment/cake/docker-tasks.cake index 4f7b989a..26e4e198 100644 --- a/deployment/cake/docker-tasks.cake +++ b/deployment/cake/docker-tasks.cake @@ -1,7 +1,7 @@ #l "docker-variables.cake" #l "lib-octopusdeploy.cake" -#addin "nuget:?package=Cake.Docker&version=1.0.0" +#addin "nuget:?package=Cake.Docker&version=1.2.0" //------------------------------------------------------------- @@ -18,19 +18,19 @@ public class DockerImagesProcessor : ProcessorBase return BuildContext.DockerImages.Items.Count > 0; } - private string GetDockerRegistryUrl(string projectName) + public string GetDockerRegistryUrl(string projectName) { // Allow per project overrides via "DockerRegistryUrlFor[ProjectName]" return GetProjectSpecificConfigurationValue(BuildContext, projectName, "DockerRegistryUrlFor", BuildContext.DockerImages.DockerRegistryUrl); } - private string GetDockerRegistryUserName(string projectName) + public string GetDockerRegistryUserName(string projectName) { // Allow per project overrides via "DockerRegistryUserNameFor[ProjectName]" return GetProjectSpecificConfigurationValue(BuildContext, projectName, "DockerRegistryUserNameFor", BuildContext.DockerImages.DockerRegistryUserName); } - private string GetDockerRegistryPassword(string projectName) + public string GetDockerRegistryPassword(string projectName) { // Allow per project overrides via "DockerRegistryPasswordFor[ProjectName]" return GetProjectSpecificConfigurationValue(BuildContext, projectName, "DockerRegistryPasswordFor", BuildContext.DockerImages.DockerRegistryPassword); @@ -47,7 +47,60 @@ public class DockerImagesProcessor : ProcessorBase var dockerRegistryUrl = GetDockerRegistryUrl(projectName); var tag = string.Format("{0}/{1}:{2}", dockerRegistryUrl, GetDockerImageName(projectName), version); - return tag.ToLower(); + return tag.TrimStart(' ', '/').ToLower(); + } + + private string[] GetDockerImageTags(string projectName) + { + var dockerTags = new List(); + + var versions = new List(); + + versions.Add(BuildContext.General.Version.NuGet); + + foreach (var version in new [] + { + BuildContext.General.Version.MajorMinor, + BuildContext.General.Version.Major + }) + { + var additionalTag = version; + + if (BuildContext.General.IsAlphaBuild) + { + additionalTag += "-alpha"; + } + + if (BuildContext.General.IsBetaBuild) + { + additionalTag += "-beta"; + } + + versions.Add(additionalTag); + } + + foreach (var version in versions) + { + dockerTags.Add(GetDockerImageTag(projectName, version)); + } + + if (BuildContext.General.IsAlphaBuild) + { + dockerTags.Add(GetDockerImageTag(projectName, "latest-alpha")); + } + + if (BuildContext.General.IsBetaBuild) + { + dockerTags.Add(GetDockerImageTag(projectName, "latest-beta")); + } + + if (BuildContext.General.IsOfficialBuild) + { + dockerTags.Add(GetDockerImageTag(projectName, "latest-stable")); + dockerTags.Add(GetDockerImageTag(projectName, "latest")); + } + + return dockerTags.ToArray(); } private void ConfigureDockerSettings(AutoToolSettings dockerSettings) @@ -73,6 +126,11 @@ public class DockerImagesProcessor : ProcessorBase // is required to prevent issues with foreach foreach (var dockerImage in BuildContext.DockerImages.Items.ToList()) { + foreach (var imageTag in GetDockerImageTags(dockerImage)) + { + CakeContext.Information(imageTag); + } + if (!ShouldProcessProject(BuildContext, dockerImage)) { BuildContext.DockerImages.Items.Remove(dockerImage); @@ -114,7 +172,8 @@ public class DockerImagesProcessor : ProcessorBase var projectFileName = GetProjectFileName(BuildContext, dockerImage); - var msBuildSettings = new MSBuildSettings { + var msBuildSettings = new MSBuildSettings + { Verbosity = Verbosity.Quiet, // Verbosity.Diagnostic ToolVersion = MSBuildToolVersion.Default, Configuration = BuildContext.General.Solution.ConfigurationName, @@ -122,21 +181,12 @@ public class DockerImagesProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, dockerImage); + ConfigureMsBuild(BuildContext, msBuildSettings, dockerImage, "build"); // Always disable SourceLink msBuildSettings.WithProperty("EnableSourceLink", "false"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = GetProjectOutputDirectory(BuildContext, dockerImage); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); - - RunMsBuild(BuildContext, dockerImage, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, dockerImage, projectFileName, msBuildSettings, "build"); } } @@ -153,9 +203,9 @@ public class DockerImagesProcessor : ProcessorBase foreach (var dockerImage in BuildContext.DockerImages.Items) { - if (!ShouldDeployProject(BuildContext, dockerImage)) + if (!ShouldPackageProject(BuildContext, dockerImage)) { - CakeContext.Information("Docker image '{0}' should not be deployed", dockerImage); + CakeContext.Information("Docker image '{0}' should not be packaged", dockerImage); continue; } @@ -188,21 +238,17 @@ public class DockerImagesProcessor : ProcessorBase var outputDirectory = System.IO.Path.Combine(outputRootDirectory, "output"); CakeContext.Information("Output directory: '{0}'", outputDirectory); - var msBuildSettings = new DotNetCoreMSBuildSettings(); + var msBuildSettings = new DotNetMSBuildSettings(); + + ConfigureMsBuildForDotNet(BuildContext, msBuildSettings, dockerImage, "pack"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", outputDirectory); msBuildSettings.WithProperty("ConfigurationName", BuildContext.General.Solution.ConfigurationName); msBuildSettings.WithProperty("PackageVersion", BuildContext.General.Version.NuGet); // Disable code analyses, we experienced publish issues with mvc .net core projects msBuildSettings.WithProperty("RunCodeAnalysis", "false"); - var publishSettings = new DotNetCorePublishSettings + var publishSettings = new DotNetPublishSettings { MSBuildSettings = msBuildSettings, OutputDirectory = outputDirectory, @@ -210,7 +256,7 @@ public class DockerImagesProcessor : ProcessorBase //NoBuild = true }; - CakeContext.DotNetCorePublish(projectFileName, publishSettings); + CakeContext.DotNetPublish(projectFileName, publishSettings); BuildContext.CakeContext.LogSeparator(); @@ -231,7 +277,7 @@ public class DockerImagesProcessor : ProcessorBase NoCache = true, // Don't use cache, always make sure to fetch the right images File = dockerImageSpecificationFileName, //Platform = "linux", - Tag = new string[] { GetDockerImageTag(dockerImage, BuildContext.General.Version.NuGet) } + Tag = GetDockerImageTags(dockerImage) }; ConfigureDockerSettings(dockerSettings); @@ -265,7 +311,6 @@ public class DockerImagesProcessor : ProcessorBase var dockerRegistryUserName = GetDockerRegistryUserName(dockerImage); var dockerRegistryPassword = GetDockerRegistryPassword(dockerImage); var dockerImageName = GetDockerImageName(dockerImage); - var dockerImageTag = GetDockerImageTag(dockerImage, BuildContext.General.Version.NuGet); var octopusRepositoryUrl = BuildContext.OctopusDeploy.GetRepositoryUrl(dockerImage); var octopusRepositoryApiKey = BuildContext.OctopusDeploy.GetRepositoryApiKey(dockerImage); var octopusDeploymentTarget = BuildContext.OctopusDeploy.GetDeploymentTarget(dockerImage); @@ -290,54 +335,57 @@ public class DockerImagesProcessor : ProcessorBase try { - CakeContext.Information("Pushing docker images with tag '{0}' to '{1}'", dockerImageTag, dockerRegistryUrl); - - var dockerImagePushSettings = new DockerImagePushSettings + foreach (var dockerImageTag in GetDockerImageTags(dockerImage)) { - }; - - ConfigureDockerSettings(dockerImagePushSettings); - - CakeContext.DockerPush(dockerImagePushSettings, dockerImageTag); + CakeContext.Information("Pushing docker images with tag '{0}' to '{1}'", dockerImageTag, dockerRegistryUrl); - if (string.IsNullOrWhiteSpace(octopusRepositoryUrl)) - { - CakeContext.Warning("Octopus Deploy url is not specified, skipping deployment to Octopus Deploy"); - continue; - } + var dockerImagePushSettings = new DockerImagePushSettings + { + }; - var imageVersion = BuildContext.General.Version.NuGet; + ConfigureDockerSettings(dockerImagePushSettings); - CakeContext.Information("Creating release '{0}' in Octopus Deploy", imageVersion); + CakeContext.DockerPush(dockerImagePushSettings, dockerImageTag); - CakeContext.OctoCreateRelease(dockerImage, new CreateReleaseSettings - { - Server = octopusRepositoryUrl, - ApiKey = octopusRepositoryApiKey, - ReleaseNumber = imageVersion, - DefaultPackageVersion = imageVersion, - IgnoreExisting = true, - Packages = new Dictionary + if (string.IsNullOrWhiteSpace(octopusRepositoryUrl)) { - { dockerImageName, imageVersion } + CakeContext.Warning("Octopus Deploy url is not specified, skipping deployment to Octopus Deploy"); + continue; } - }); - CakeContext.Information("Deploying release '{0}' via Octopus Deploy", imageVersion); + var imageVersion = BuildContext.General.Version.NuGet; - CakeContext.OctoDeployRelease(octopusRepositoryUrl, octopusRepositoryApiKey, dockerImage, octopusDeploymentTarget, - imageVersion, new OctopusDeployReleaseDeploymentSettings - { - ShowProgress = true, - WaitForDeployment = true, - DeploymentTimeout = TimeSpan.FromMinutes(5), - CancelOnTimeout = true, - GuidedFailure = true, - Force = true, - NoRawLog = true, - }); - - await BuildContext.Notifications.NotifyAsync(dockerImage, string.Format("Deployed to Octopus Deploy"), TargetType.DockerImage); + CakeContext.Information("Creating release '{0}' in Octopus Deploy", imageVersion); + + CakeContext.OctoCreateRelease(dockerImage, new CreateReleaseSettings + { + Server = octopusRepositoryUrl, + ApiKey = octopusRepositoryApiKey, + ReleaseNumber = imageVersion, + DefaultPackageVersion = imageVersion, + IgnoreExisting = true, + Packages = new Dictionary + { + { dockerImageName, imageVersion } + } + }); + + CakeContext.Information("Deploying release '{0}' via Octopus Deploy", imageVersion); + + CakeContext.OctoDeployRelease(octopusRepositoryUrl, octopusRepositoryApiKey, dockerImage, octopusDeploymentTarget, + imageVersion, new OctopusDeployReleaseDeploymentSettings + { + ShowProgress = true, + WaitForDeployment = true, + DeploymentTimeout = TimeSpan.FromMinutes(5), + CancelOnTimeout = true, + GuidedFailure = true, + Force = true, + NoRawLog = true, + }); + + await BuildContext.Notifications.NotifyAsync(dockerImage, string.Format("Deployed to Octopus Deploy"), TargetType.DockerImage); + } } finally { diff --git a/deployment/cake/generic-tasks.cake b/deployment/cake/generic-tasks.cake index a2a3fe0f..d06bfaa9 100644 --- a/deployment/cake/generic-tasks.cake +++ b/deployment/cake/generic-tasks.cake @@ -3,7 +3,6 @@ //#addin "nuget:?package=Cake.DependencyCheck&version=1.2.0" //#tool "nuget:?package=DependencyCheck.Runner.Tool&version=3.2.1&include=./**/dependency-check.sh&include=./**/dependency-check.bat" -//#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.1.3" //------------------------------------------------------------- @@ -38,8 +37,8 @@ private void CleanUpCode(bool failOnChanges) // arguments.Add("--check"); // } - // DotNetCoreTool(null, "format", string.Join(" ", arguments), - // new DotNetCoreToolSettings + // DotNetTool(null, "format", string.Join(" ", arguments), + // new DotNetToolSettings // { // WorkingDirectory = "./src/" // }); @@ -89,30 +88,33 @@ Task("UpdateNuGet") .ContinueOnError() .Does(buildContext => { - Information("Making sure NuGet is using the latest version"); + // DISABLED UNTIL NUGET GETS FIXED: https://github.com/NuGet/Home/issues/10853 - if (buildContext.General.IsLocalBuild && buildContext.General.MaximizePerformance) - { - Information("Local build with maximized performance detected, skipping NuGet update check"); - return; - } + // Information("Making sure NuGet is using the latest version"); - var nuGetExecutable = buildContext.General.NuGet.Executable; + // if (buildContext.General.IsLocalBuild && buildContext.General.MaximizePerformance) + // { + // Information("Local build with maximized performance detected, skipping NuGet update check"); + // return; + // } - var exitCode = StartProcess(nuGetExecutable, new ProcessSettings - { - Arguments = "update -self" - }); + // var nuGetExecutable = buildContext.General.NuGet.Executable; - var newNuGetVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(nuGetExecutable); - var newNuGetVersion = newNuGetVersionInfo.FileVersion; + // var exitCode = StartProcess(nuGetExecutable, new ProcessSettings + // { + // Arguments = "update -self" + // }); + + // var newNuGetVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(nuGetExecutable); + // var newNuGetVersion = newNuGetVersionInfo.FileVersion; - Information("Updating NuGet.exe exited with '{0}', version is '{1}'", exitCode, newNuGetVersion); + // Information("Updating NuGet.exe exited with '{0}', version is '{1}'", exitCode, newNuGetVersion); }); //------------------------------------------------------------- Task("RestorePackages") + .IsDependentOn("Prepare") .IsDependentOn("UpdateNuGet") .ContinueOnError() .Does(buildContext => @@ -130,18 +132,17 @@ Task("RestorePackages") foreach (var project in buildContext.AllProjects) { - if (ShouldProcessProject(buildContext, project)) + // Once a project is in AllProjects, it should always be restored + + var projectFileName = GetProjectFileName(buildContext, project); + if (projectFileName.EndsWith(".csproj")) { - var projectFileName = GetProjectFileName(buildContext, project); - if (projectFileName.EndsWith(".csproj")) - { - Information("Adding '{0}' as C# specific project to restore", project); + Information("Adding '{0}' as C# specific project to restore", project); - csharpProjects.Add(projectFileName); + csharpProjects.Add(projectFileName); - // Inject source link *before* package restore - InjectSourceLinkInProjectFile(buildContext, projectFileName); - } + // Inject source link *before* package restore + InjectSourceLinkInProjectFile(buildContext, project, projectFileName); } } @@ -150,6 +151,8 @@ Task("RestorePackages") allFiles.AddRange(csharpProjects); // //allFiles.AddRange(cProjects); + Information($"Found '{allFiles.Count}' projects to restore"); + foreach (var file in allFiles) { RestoreNuGetPackages(buildContext, file); @@ -179,6 +182,7 @@ Task("RestorePackages") Task("Clean") //.IsDependentOn("RestorePackages") + .IsDependentOn("Prepare") .ContinueOnError() .Does(buildContext => { @@ -312,7 +316,8 @@ Task("CodeSign") filesToSign.AddRange(projectFilesToSign); } - var signToolCommand = string.Format("sign /a /t {0} /n {1}", buildContext.General.CodeSign.TimeStampUri, certificateSubjectName); + var signToolCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", buildContext.General.CodeSign.TimeStampUri, + certificateSubjectName, buildContext.General.CodeSign.HashAlgorithm); SignFiles(buildContext, signToolCommand, filesToSign); diff --git a/deployment/cake/generic-variables.cake b/deployment/cake/generic-variables.cake index 726602f0..cb915fa3 100644 --- a/deployment/cake/generic-variables.cake +++ b/deployment/cake/generic-variables.cake @@ -1,6 +1,6 @@ #l "buildserver.cake" -#tool "nuget:?package=GitVersion.CommandLine&version=5.6.6" +#tool "nuget:?package=GitVersion.CommandLine&version=5.12.0" //------------------------------------------------------------- @@ -67,7 +67,7 @@ public class VersionContext : BuildContextBase var gitVersionSettings = new GitVersionSettings { UpdateAssemblyInfo = false, - Verbosity = GitVersionVerbosity.Debug + Verbosity = GitVersionVerbosity.Verbose }; var gitDirectory = ".git"; @@ -115,7 +115,7 @@ public class VersionContext : BuildContextBase gitVersionSettings.NoFetch = false; gitVersionSettings.WorkingDirectory = generalContext.RootDirectory; gitVersionSettings.DynamicRepositoryPath = dynamicRepositoryPath; - gitVersionSettings.Verbosity = GitVersionVerbosity.Debug; + gitVersionSettings.Verbosity = GitVersionVerbosity.Verbose; } _gitVersionContext = CakeContext.GitVersion(gitVersionSettings); @@ -125,11 +125,64 @@ public class VersionContext : BuildContextBase } public bool ClearCache { get; set; } + + private string _major; + + public string Major + { + get + { + if (string.IsNullOrWhiteSpace(_major)) + { + _major = GetVersion(MajorMinorPatch, 1); + } + + return _major; + } + } + + private string _majorMinor; + + public string MajorMinor + { + get + { + if (string.IsNullOrWhiteSpace(_majorMinor)) + { + _majorMinor = GetVersion(MajorMinorPatch, 2); + } + + return _majorMinor; + } + } + public string MajorMinorPatch { get; set; } public string FullSemVer { get; set; } public string NuGet { get; set; } public string CommitsSinceVersionSource { get; set; } + private string GetVersion(string version, int breakCount) + { + var finalVersion = string.Empty; + + for (int i = 0; i < version.Length; i++) + { + var character = version[i]; + if (!char.IsDigit(character)) + { + breakCount--; + if (breakCount <= 0) + { + break; + } + } + + finalVersion += character.ToString(); + } + + return finalVersion; + } + protected override void ValidateContext() { @@ -180,6 +233,10 @@ public class NuGetContext : BuildContextBase public string Executable { get; set; } public string LocalPackagesDirectory { get; set; } + public bool RestoreUsingNuGet { get; set; } + public bool RestoreUsingDotNetRestore { get; set; } + public bool NoDependencies { get; set; } + protected override void ValidateContext() { @@ -187,7 +244,8 @@ public class NuGetContext : BuildContextBase protected override void LogStateInfoForContext() { - + CakeContext.Information($"Restore using NuGet: '{RestoreUsingNuGet}'"); + CakeContext.Information($"Restore using dotnet restore: '{RestoreUsingDotNetRestore}'"); } } @@ -271,6 +329,7 @@ public class CodeSignContext : BuildContextBase public string WildCard { get; set; } public string CertificateSubjectName { get; set; } public string TimeStampUri { get; set; } + public string HashAlgorithm { get; set; } protected override void ValidateContext() { @@ -279,7 +338,15 @@ public class CodeSignContext : BuildContextBase protected override void LogStateInfoForContext() { - + if (string.IsNullOrWhiteSpace(CertificateSubjectName)) + { + CakeContext.Information($"Code signing is not configured"); + return; + } + + CakeContext.Information($"Code signing subject name: '{CertificateSubjectName}'"); + CakeContext.Information($"Code signing timestamp uri: '{TimeStampUri}'"); + CakeContext.Information($"Code signing hash algorithm: '{HashAlgorithm}'"); } } @@ -368,7 +435,10 @@ private GeneralContext InitializeGeneralContext(BuildContext buildContext, IBuil { PackageSources = buildContext.BuildServer.GetVariable("NuGetPackageSources", showValue: true), Executable = "./tools/nuget.exe", - LocalPackagesDirectory = "c:\\source\\_packages" + LocalPackagesDirectory = "c:\\source\\_packages", + RestoreUsingNuGet = buildContext.BuildServer.GetVariableAsBool("NuGet_RestoreUsingNuGet", false, showValue: true), + RestoreUsingDotNetRestore = buildContext.BuildServer.GetVariableAsBool("NuGet_RestoreUsingDotNetRestore", true, showValue: true), + NoDependencies = buildContext.BuildServer.GetVariableAsBool("NuGet_NoDependencies", true, showValue: true) }; var solutionName = buildContext.BuildServer.GetVariable("SolutionName", showValue: true); @@ -413,7 +483,8 @@ private GeneralContext InitializeGeneralContext(BuildContext buildContext, IBuil { WildCard = buildContext.BuildServer.GetVariable("CodeSignWildcard", showValue: true), CertificateSubjectName = buildContext.BuildServer.GetVariable("CodeSignCertificateSubjectName", showValue: true), - TimeStampUri = buildContext.BuildServer.GetVariable("CodeSignTimeStampUri", "http://timestamp.digicert.com", showValue: true) + TimeStampUri = buildContext.BuildServer.GetVariable("CodeSignTimeStampUri", "http://timestamp.digicert.com", showValue: true), + HashAlgorithm = buildContext.BuildServer.GetVariable("CodeSignHashAlgorithm", "SHA256", showValue: true) }; data.Repository = new RepositoryContext(data) @@ -533,4 +604,4 @@ private static string DeterminePublishType(GeneralContext context) } return publishType; -} \ No newline at end of file +} diff --git a/deployment/cake/github-pages-tasks.cake b/deployment/cake/github-pages-tasks.cake index aa1d023a..985ba98d 100644 --- a/deployment/cake/github-pages-tasks.cake +++ b/deployment/cake/github-pages-tasks.cake @@ -1,6 +1,6 @@ #l "github-pages-variables.cake" -#addin "nuget:?package=Cake.Git&version=1.0.0" +#addin "nuget:?package=Cake.Git&version=3.0.0" //------------------------------------------------------------- @@ -106,21 +106,12 @@ public class GitHubPagesProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, gitHubPage); + ConfigureMsBuild(BuildContext, msBuildSettings, gitHubPage, "build"); // Always disable SourceLink msBuildSettings.WithProperty("EnableSourceLink", "false"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = GetProjectOutputDirectory(BuildContext, gitHubPage); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); - - RunMsBuild(BuildContext, gitHubPage, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, gitHubPage, projectFileName, msBuildSettings, "build"); } } @@ -133,9 +124,9 @@ public class GitHubPagesProcessor : ProcessorBase foreach (var gitHubPage in BuildContext.GitHubPages.Items) { - if (!ShouldDeployProject(BuildContext, gitHubPage)) + if (!ShouldPackageProject(BuildContext, gitHubPage)) { - CakeContext.Information("GitHub page '{0}' should not be deployed", gitHubPage); + CakeContext.Information("GitHub page '{0}' should not be packaged", gitHubPage); continue; } @@ -148,25 +139,21 @@ public class GitHubPagesProcessor : ProcessorBase CakeContext.Information("1) Using 'dotnet publish' to package '{0}'", gitHubPage); - var msBuildSettings = new DotNetCoreMSBuildSettings(); + var msBuildSettings = new DotNetMSBuildSettings(); + + ConfigureMsBuildForDotNet(BuildContext, msBuildSettings, gitHubPage, "pack"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", outputDirectory); msBuildSettings.WithProperty("ConfigurationName", BuildContext.General.Solution.ConfigurationName); msBuildSettings.WithProperty("PackageVersion", BuildContext.General.Version.NuGet); - var publishSettings = new DotNetCorePublishSettings + var publishSettings = new DotNetPublishSettings { MSBuildSettings = msBuildSettings, OutputDirectory = outputDirectory, Configuration = BuildContext.General.Solution.ConfigurationName }; - CakeContext.DotNetCorePublish(projectFileName, publishSettings); + CakeContext.DotNetPublish(projectFileName, publishSettings); } } diff --git a/deployment/cake/installers-innosetup.cake b/deployment/cake/installers-innosetup.cake index 3077d5c9..344a2d1f 100644 --- a/deployment/cake/installers-innosetup.cake +++ b/deployment/cake/installers-innosetup.cake @@ -21,6 +21,8 @@ public class InnoSetupInstaller : IInstaller public bool IsAvailable { get; private set; } + //------------------------------------------------------------- + public async Task PackageAsync(string projectName, string channel) { if (!IsAvailable) @@ -100,4 +102,124 @@ public class InnoSetupInstaller : IInstaller BuildContext.CakeContext.CopyFile(installerSourceFile, System.IO.Path.Combine(installersOnDeploymentsShare, $"{projectName}{setupSuffix}.exe")); } } + + //------------------------------------------------------------- + + public async Task GenerateDeploymentTargetAsync(string projectName) + { + var deploymentTarget = new DeploymentTarget + { + Name = "Inno Setup" + }; + + var channels = new [] + { + "alpha", + "beta", + "stable" + }; + + var deploymentGroupNames = new List(); + var projectDeploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + // Just a single group + deploymentGroupNames.Add("all"); + + foreach (var deploymentGroupName in deploymentGroupNames) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment group '{deploymentGroupName}'"); + + var deploymentGroup = new DeploymentGroup + { + Name = deploymentGroupName + }; + + foreach (var channel in channels) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment channel '{deploymentGroupName}/{channel}'"); + + var deploymentChannel = new DeploymentChannel + { + Name = channel + }; + + var targetDirectory = GetDeploymentsShareRootDirectory(projectName, channel); + + BuildContext.CakeContext.Information($"Searching for release files in '{targetDirectory}'"); + + var filter = $"{projectName}_*{channel}*.exe"; + if (channel == "stable") + { + filter = $"{projectName}_*.exe"; + } + + var installationFiles = System.IO.Directory.GetFiles(targetDirectory, filter); + + foreach (var installationFile in installationFiles) + { + var releaseFileInfo = new System.IO.FileInfo(installationFile); + var relativeFileName = new DirectoryPath(projectDeploymentShare).GetRelativePath(new FilePath(releaseFileInfo.FullName)).FullPath.Replace("\\", "/"); + + var releaseVersion = releaseFileInfo.Name + .Replace($"{projectName}", string.Empty) + .Replace($".exe", string.Empty) + .Trim('_'); + + // Either empty or matching a release channel should be ignored + if (string.IsNullOrWhiteSpace(releaseVersion) || + channels.Any(x => x == releaseVersion)) + { + BuildContext.CakeContext.Information($"Ignoring '{installationFile}'"); + continue; + } + + // Special case for stable releases + if (channel == "stable") + { + if (releaseVersion.Contains("-alpha") || + releaseVersion.Contains("-beta")) + { + BuildContext.CakeContext.Information($"Ignoring '{installationFile}'"); + continue; + } + } + + BuildContext.CakeContext.Information($"Applying release based on '{installationFile}'"); + + var release = new DeploymentRelease + { + Name = releaseVersion, + Timestamp = releaseFileInfo.CreationTimeUtc + }; + + // Full release + release.Full = new DeploymentReleasePart + { + RelativeFileName = relativeFileName, + Size = (ulong)releaseFileInfo.Length + }; + + deploymentChannel.Releases.Add(release); + } + + deploymentGroup.Channels.Add(deploymentChannel); + } + + deploymentTarget.Groups.Add(deploymentGroup); + } + + return deploymentTarget; + } + + //------------------------------------------------------------- + + private string GetDeploymentsShareRootDirectory(string projectName, string channel) + { + var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + var installersOnDeploymentsShare = System.IO.Path.Combine(deploymentShare, "installer"); + BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); + + return installersOnDeploymentsShare; + } } diff --git a/deployment/cake/installers-msix.cake b/deployment/cake/installers-msix.cake index 92143302..4aa88974 100644 --- a/deployment/cake/installers-msix.cake +++ b/deployment/cake/installers-msix.cake @@ -27,6 +27,8 @@ public class MsixInstaller : IInstaller public bool IsAvailable { get; private set; } + //------------------------------------------------------------- + public async Task PackageAsync(string projectName, string channel) { if (!IsAvailable) @@ -52,8 +54,8 @@ public class MsixInstaller : IInstaller var signToolCommand = string.Empty; if (!string.IsNullOrWhiteSpace(BuildContext.General.CodeSign.CertificateSubjectName)) { - signToolCommand = string.Format("sign /a /t {0} /n {1}", BuildContext.General.CodeSign.TimeStampUri, - BuildContext.General.CodeSign.CertificateSubjectName); + signToolCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", BuildContext.General.CodeSign.TimeStampUri, + BuildContext.General.CodeSign.CertificateSubjectName, BuildContext.General.CodeSign.HashAlgorithm); } else { @@ -63,9 +65,7 @@ public class MsixInstaller : IInstaller BuildContext.CakeContext.LogSeparator($"Packaging app '{projectName}' using MSIX"); var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); - - var installersOnDeploymentsShare = System.IO.Path.Combine(deploymentShare, channel, "msix"); - BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); + var installersOnDeploymentsShare = GetDeploymentsShareRootDirectory(projectName, channel); var setupSuffix = BuildContext.Installer.GetDeploymentChannelSuffix(); @@ -154,9 +154,7 @@ public class MsixInstaller : IInstaller } } - // As documented at https://docs.microsoft.com/en-us/windows/msix/package/sign-app-package-using-signtool, we - // must *always* specify the hash algorithm (/fd) for MSIX files - SignFile(BuildContext, signToolCommand, installerSourceFile, "/fd SHA256"); + SignFile(BuildContext, signToolCommand, installerSourceFile); // Always copy the AppInstaller if available if (BuildContext.CakeContext.FileExists(msixUpdateScriptFileName)) @@ -186,6 +184,163 @@ public class MsixInstaller : IInstaller } } + //------------------------------------------------------------- + + public async Task GenerateDeploymentTargetAsync(string projectName) + { + var deploymentTarget = new DeploymentTarget + { + Name = "MSIX" + }; + + var channels = new [] + { + "alpha", + "beta", + "stable" + }; + + var deploymentGroupNames = new List(); + var projectDeploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + if (BuildContext.Wpf.GroupUpdatesByMajorVersion) + { + // Check every directory that we can parse as number + var directories = System.IO.Directory.GetDirectories(projectDeploymentShare); + + foreach (var directory in directories) + { + var deploymentGroupName = new System.IO.DirectoryInfo(directory).Name; + + if (int.TryParse(deploymentGroupName, out _)) + { + deploymentGroupNames.Add(deploymentGroupName); + } + } + } + else + { + // Just a single group + deploymentGroupNames.Add("all"); + } + + foreach (var deploymentGroupName in deploymentGroupNames) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment group '{deploymentGroupName}'"); + + var deploymentGroup = new DeploymentGroup + { + Name = deploymentGroupName + }; + + var version = deploymentGroupName; + if (version == "all") + { + version = string.Empty; + } + + foreach (var channel in channels) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment channel '{deploymentGroupName}/{channel}'"); + + var deploymentChannel = new DeploymentChannel + { + Name = channel + }; + + var targetDirectory = GetDeploymentsShareRootDirectory(projectName, channel, version); + + BuildContext.CakeContext.Information($"Searching for release files in '{targetDirectory}'"); + + var msixFiles = System.IO.Directory.GetFiles(targetDirectory, "*.msix"); + + foreach (var msixFile in msixFiles) + { + var releaseFileInfo = new System.IO.FileInfo(msixFile); + var relativeFileName = new DirectoryPath(projectDeploymentShare).GetRelativePath(new FilePath(releaseFileInfo.FullName)).FullPath.Replace("\\", "/"); + var releaseVersion = releaseFileInfo.Name + .Replace($"{projectName}_", string.Empty) + .Replace($".msix", string.Empty); + + // Either empty or matching a release channel should be ignored + if (string.IsNullOrWhiteSpace(releaseVersion) || + channels.Any(x => x == releaseVersion)) + { + BuildContext.CakeContext.Information($"Ignoring '{msixFile}'"); + continue; + } + + // Special case for stable releases + if (channel == "stable") + { + if (releaseVersion.Contains("-alpha") || + releaseVersion.Contains("-beta")) + { + BuildContext.CakeContext.Information($"Ignoring '{msixFile}'"); + continue; + } + } + + BuildContext.CakeContext.Information($"Applying release based on '{msixFile}'"); + + var release = new DeploymentRelease + { + Name = releaseVersion, + Timestamp = releaseFileInfo.CreationTimeUtc + }; + + // Only support full versions + release.Full = new DeploymentReleasePart + { + RelativeFileName = relativeFileName, + Size = (ulong)releaseFileInfo.Length + }; + + deploymentChannel.Releases.Add(release); + } + + deploymentGroup.Channels.Add(deploymentChannel); + } + + deploymentTarget.Groups.Add(deploymentGroup); + } + + return deploymentTarget; + } + + //------------------------------------------------------------- + + private string GetDeploymentsShareRootDirectory(string projectName, string channel) + { + var version = string.Empty; + + if (BuildContext.Wpf.GroupUpdatesByMajorVersion) + { + version = BuildContext.General.Version.Major; + } + + return GetDeploymentsShareRootDirectory(projectName, channel, version); + } + + //------------------------------------------------------------- + + private string GetDeploymentsShareRootDirectory(string projectName, string channel, string version) + { + var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + if (!string.IsNullOrWhiteSpace(version)) + { + deploymentShare = System.IO.Path.Combine(deploymentShare, version); + } + + var installersOnDeploymentsShare = System.IO.Path.Combine(deploymentShare, channel, "msix"); + BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); + + return installersOnDeploymentsShare; + } + + //------------------------------------------------------------- + private void ReplaceVariablesInFile(string fileName, Dictionary variables) { var fileContents = System.IO.File.ReadAllText(fileName); @@ -198,6 +353,8 @@ public class MsixInstaller : IInstaller System.IO.File.WriteAllText(fileName, fileContents); } + //------------------------------------------------------------- + private string FindLatestMakeAppxFileName() { var directory = FindLatestWindowsKitsDirectory(BuildContext); diff --git a/deployment/cake/installers-squirrel.cake b/deployment/cake/installers-squirrel.cake index a102328b..10ac3f22 100644 --- a/deployment/cake/installers-squirrel.cake +++ b/deployment/cake/installers-squirrel.cake @@ -1,4 +1,4 @@ -#addin "nuget:?package=Cake.Squirrel&version=0.15.1" +#addin "nuget:?package=Cake.Squirrel&version=0.15.2" #tool "nuget:?package=Squirrel.Windows&version=2.0.1" @@ -25,6 +25,8 @@ public class SquirrelInstaller : IInstaller public bool IsAvailable { get; private set; } + //------------------------------------------------------------- + public async Task PackageAsync(string projectName, string channel) { if (!IsAvailable) @@ -33,7 +35,24 @@ public class SquirrelInstaller : IInstaller return; } - var squirrelOutputRoot = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "squirrel", projectName, channel); + // There are 2 flavors: + // + // 1: Non-grouped: /[app]/[channel] (e.g. /MyApp/alpha) + // Updates will always be applied, even to new major versions + // + // 2: Grouped by major version: /[app]/[major_version]/[channel] (e.g. /MyApp/4/alpha) + // Updates will only be applied to non-major updates. This allows manual migration to + // new major versions, which is very useful when there are dependencies that need to + // be updated before a new major version can be switched to. + var squirrelOutputRoot = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "squirrel", projectName); + + if (BuildContext.Wpf.GroupUpdatesByMajorVersion) + { + squirrelOutputRoot = System.IO.Path.Combine(squirrelOutputRoot, BuildContext.General.Version.Major); + } + + squirrelOutputRoot = System.IO.Path.Combine(squirrelOutputRoot, channel); + var squirrelReleasesRoot = System.IO.Path.Combine(squirrelOutputRoot, "releases"); var squirrelOutputIntermediate = System.IO.Path.Combine(squirrelOutputRoot, "intermediate"); @@ -101,15 +120,23 @@ public class SquirrelInstaller : IInstaller if (!string.IsNullOrWhiteSpace(BuildContext.General.CodeSign.CertificateSubjectName)) { + // Note: Squirrel uses it's own sign tool, so make sure to follow their specs signToolCommand = string.Format("/a /t {0} /n {1}", BuildContext.General.CodeSign.TimeStampUri, BuildContext.General.CodeSign.CertificateSubjectName); } - // Create NuGet package - BuildContext.CakeContext.NuGetPack(nuSpecFileName, new NuGetPackSettings + var nuGetSettings = new NuGetPackSettings { + NoPackageAnalysis = true, OutputDirectory = squirrelOutputIntermediate, - }); + Verbosity = NuGetVerbosity.Detailed, + }; + + // Fix for target framework issues + nuGetSettings.Properties.Add("TargetPlatformVersion", "7.0"); + + // Create NuGet package + BuildContext.CakeContext.NuGetPack(nuSpecFileName, nuGetSettings); // Rename so we have the right nuget package file names (without the channel) if (!string.IsNullOrWhiteSpace(setupSuffix)) @@ -121,13 +148,15 @@ public class SquirrelInstaller : IInstaller BuildContext.CakeContext.MoveFile(sourcePackageFileName, targetPackageFileName); } - - var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); // Copy deployments share to the intermediate root so we can locally create the Squirrel releases - var releasesSourceDirectory = System.IO.Path.Combine(deploymentShare, channel); + + var releasesSourceDirectory = GetDeploymentsShareRootDirectory(projectName, channel); var releasesTargetDirectory = squirrelReleasesRoot; + BuildContext.CakeContext.CreateDirectory(releasesSourceDirectory); + BuildContext.CakeContext.CreateDirectory(releasesTargetDirectory); + BuildContext.CakeContext.Information("Copying releases from '{0}' => '{1}'", releasesSourceDirectory, releasesTargetDirectory); BuildContext.CakeContext.CopyDirectory(releasesSourceDirectory, releasesTargetDirectory); @@ -173,4 +202,161 @@ public class SquirrelInstaller : IInstaller BuildContext.CakeContext.CopyFile(System.IO.Path.Combine(squirrelReleasesRoot, "RELEASES"), System.IO.Path.Combine(releasesSourceDirectory, "RELEASES")); } } + + //------------------------------------------------------------- + + public async Task GenerateDeploymentTargetAsync(string projectName) + { + var deploymentTarget = new DeploymentTarget + { + Name = "Squirrel" + }; + + var channels = new [] + { + "alpha", + "beta", + "stable" + }; + + var deploymentGroupNames = new List(); + var projectDeploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + if (BuildContext.Wpf.GroupUpdatesByMajorVersion) + { + // Check every directory that we can parse as number + var directories = System.IO.Directory.GetDirectories(projectDeploymentShare); + + foreach (var directory in directories) + { + var deploymentGroupName = new System.IO.DirectoryInfo(directory).Name; + + if (int.TryParse(deploymentGroupName, out _)) + { + deploymentGroupNames.Add(deploymentGroupName); + } + } + } + else + { + // Just a single group + deploymentGroupNames.Add("all"); + } + + foreach (var deploymentGroupName in deploymentGroupNames) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment group '{deploymentGroupName}'"); + + var deploymentGroup = new DeploymentGroup + { + Name = deploymentGroupName + }; + + var version = deploymentGroupName; + if (version == "all") + { + version = string.Empty; + } + + foreach (var channel in channels) + { + BuildContext.CakeContext.Information($"Searching for releases for deployment channel '{deploymentGroupName}/{channel}'"); + + var deploymentChannel = new DeploymentChannel + { + Name = channel + }; + + var targetDirectory = GetDeploymentsShareRootDirectory(projectName, channel, version); + + BuildContext.CakeContext.Information($"Searching for release files in '{targetDirectory}'"); + + var fullNupkgFiles = System.IO.Directory.GetFiles(targetDirectory, "*-full.nupkg"); + + foreach (var fullNupkgFile in fullNupkgFiles) + { + BuildContext.CakeContext.Information($"Applying release based on '{fullNupkgFile}'"); + + var fullReleaseFileInfo = new System.IO.FileInfo(fullNupkgFile); + var fullRelativeFileName = new DirectoryPath(projectDeploymentShare).GetRelativePath(new FilePath(fullReleaseFileInfo.FullName)).FullPath.Replace("\\", "/"); + + var releaseVersion = fullReleaseFileInfo.Name + .Replace($"{projectName}_{channel}-", string.Empty) + .Replace($"-full.nupkg", string.Empty); + + // Exception for full releases, they don't contain the channel name + if (channel == "stable") + { + releaseVersion = releaseVersion.Replace($"{projectName}-", string.Empty); + } + + var release = new DeploymentRelease + { + Name = releaseVersion, + Timestamp = fullReleaseFileInfo.CreationTimeUtc + }; + + // Full release + release.Full = new DeploymentReleasePart + { + RelativeFileName = fullRelativeFileName, + Size = (ulong)fullReleaseFileInfo.Length + }; + + // Delta release + var deltaNupkgFile = fullNupkgFile.Replace("-full.nupkg", "-delta.nupkg"); + if (System.IO.File.Exists(deltaNupkgFile)) + { + var deltaReleaseFileInfo = new System.IO.FileInfo(deltaNupkgFile); + var deltafullRelativeFileName = new DirectoryPath(projectDeploymentShare).GetRelativePath(new FilePath(deltaReleaseFileInfo.FullName)).FullPath.Replace("\\", "/"); + + release.Delta = new DeploymentReleasePart + { + RelativeFileName = deltafullRelativeFileName, + Size = (ulong)deltaReleaseFileInfo.Length + }; + } + + deploymentChannel.Releases.Add(release); + } + + deploymentGroup.Channels.Add(deploymentChannel); + } + + deploymentTarget.Groups.Add(deploymentGroup); + } + + return deploymentTarget; + } + + //------------------------------------------------------------- + + private string GetDeploymentsShareRootDirectory(string projectName, string channel) + { + var version = string.Empty; + + if (BuildContext.Wpf.GroupUpdatesByMajorVersion) + { + version = BuildContext.General.Version.Major; + } + + return GetDeploymentsShareRootDirectory(projectName, channel, version); + } + + //------------------------------------------------------------- + + private string GetDeploymentsShareRootDirectory(string projectName, string channel, string version) + { + var deploymentShare = BuildContext.Wpf.GetDeploymentShareForProject(projectName); + + if (!string.IsNullOrWhiteSpace(version)) + { + deploymentShare = System.IO.Path.Combine(deploymentShare, version); + } + + var installersOnDeploymentsShare = System.IO.Path.Combine(deploymentShare, channel); + BuildContext.CakeContext.CreateDirectory(installersOnDeploymentsShare); + + return installersOnDeploymentsShare; + } } \ No newline at end of file diff --git a/deployment/cake/installers.cake b/deployment/cake/installers.cake index 326581fe..634ff50f 100644 --- a/deployment/cake/installers.cake +++ b/deployment/cake/installers.cake @@ -12,6 +12,96 @@ public interface IInstaller bool IsAvailable { get; } Task PackageAsync(string projectName, string channel); + + Task GenerateDeploymentTargetAsync(string projectName); +} + +//------------------------------------------------------------- + +public class DeploymentCatalog +{ + public DeploymentCatalog() + { + Targets = new List(); + } + + public List Targets { get; private set; } +} + +//------------------------------------------------------------- + +public class DeploymentTarget +{ + public DeploymentTarget() + { + Groups = new List(); + } + + public string Name { get; set; } + + public List Groups { get; private set; } +} + +//------------------------------------------------------------- + +public class DeploymentGroup +{ + public DeploymentGroup() + { + Channels = new List(); + } + + public string Name { get; set; } + + public List Channels { get; private set; } +} + +//------------------------------------------------------------- + +public class DeploymentChannel +{ + public DeploymentChannel() + { + Releases = new List(); + } + + public string Name { get; set; } + + public List Releases { get; private set; } +} + +//------------------------------------------------------------- + +public class DeploymentRelease +{ + public string Name { get; set; } + + public DateTime? Timestamp { get; set;} + + public bool HasFull + { + get { return Full is not null; } + } + + public DeploymentReleasePart Full { get; set; } + + public bool HasDelta + { + get { return Delta is not null; } + } + + public DeploymentReleasePart Delta { get; set; } +} + +//------------------------------------------------------------- + +public class DeploymentReleasePart +{ + public string Hash { get; set; } + + public string RelativeFileName { get; set; } + + public ulong Size { get; set; } } //------------------------------------------------------------- @@ -72,5 +162,42 @@ public class InstallerIntegration : IntegrationBase BuildContext.CakeContext.Information($"Installer took {stopwatch.Elapsed}"); } } + + if (BuildContext.Wpf.GenerateDeploymentCatalog) + { + BuildContext.CakeContext.LogSeparator($"Generating deployment catalog for '{projectName}'"); + + var catalog = new DeploymentCatalog(); + + foreach (var installer in _installers) + { + if (!installer.IsAvailable) + { + continue; + } + + BuildContext.CakeContext.LogSeparator($"Generating deployment target for catalog for installer '{installer.GetType().Name}' for '{projectName}'"); + + var deploymentTarget = await installer.GenerateDeploymentTargetAsync(projectName); + if (deploymentTarget is not null) + { + catalog.Targets.Add(deploymentTarget); + } + } + + var localCatalogDirectory = System.IO.Path.Combine(BuildContext.General.OutputRootDirectory, "catalog", projectName); + BuildContext.CakeContext.CreateDirectory(localCatalogDirectory); + + var localCatalogFileName = System.IO.Path.Combine(localCatalogDirectory, "catalog.json"); + var json = Newtonsoft.Json.JsonConvert.SerializeObject(catalog); + + System.IO.File.WriteAllText(localCatalogFileName, json); + + if (BuildContext.Wpf.UpdateDeploymentsShare) + { + var targetFileName = System.IO.Path.Combine(BuildContext.Wpf.GetDeploymentShareForProject(projectName), "catalog.json"); + BuildContext.CakeContext.CopyFile(localCatalogFileName, targetFileName); + } + } } } \ No newline at end of file diff --git a/deployment/cake/issuetrackers-github.cake b/deployment/cake/issuetrackers-github.cake index 809d04a4..bfeb81a5 100644 --- a/deployment/cake/issuetrackers-github.cake +++ b/deployment/cake/issuetrackers-github.cake @@ -1,4 +1,4 @@ -#tool "nuget:?package=gitreleasemanager&version=0.11.0" +#tool "nuget:?package=gitreleasemanager&version=0.13.0" //------------------------------------------------------------- diff --git a/deployment/cake/lib-generic.cake b/deployment/cake/lib-generic.cake index fc48e943..46cdf03c 100644 --- a/deployment/cake/lib-generic.cake +++ b/deployment/cake/lib-generic.cake @@ -3,6 +3,7 @@ using System.Reflection; //------------------------------------------------------------- private static readonly Dictionary _dotNetCoreCache = new Dictionary(); +private static readonly Dictionary _blazorCache = new Dictionary(); //------------------------------------------------------------- @@ -263,13 +264,6 @@ private static List SplitSeparatedList(string value, params char[] separ //------------------------------------------------------------- -private static bool IsCppProject(string projectName) -{ - return projectName.EndsWith(".vcxproj"); -} - -//------------------------------------------------------------- - private static string GetProjectDirectory(string projectName) { var projectDirectory = System.IO.Path.Combine(".", "src", projectName); @@ -441,6 +435,44 @@ private static void DeleteDirectoryWithLogging(BuildContext buildContext, string //------------------------------------------------------------- +private static bool IsCppProject(string projectName) +{ + return projectName.EndsWith(".vcxproj"); +} + +//------------------------------------------------------------- + +private static bool IsBlazorProject(BuildContext buildContext, string projectName) +{ + var projectFileName = GetProjectFileName(buildContext, projectName); + + if (!_blazorCache.TryGetValue(projectFileName, out var isBlazor)) + { + isBlazor = false; + + var lines = System.IO.File.ReadAllLines(projectFileName); + foreach (var line in lines) + { + // Match both *TargetFramework* and *TargetFrameworks* + var lowerCase = line.ToLower(); + if (lowerCase.Contains(" Excludes var includes = buildContext.General.Includes; if (includes.Count > 0) @@ -510,6 +565,13 @@ private static bool ShouldProcessProject(BuildContext buildContext, string proje return process; } + // Is this a known project? + if (!buildContext.RegisteredProjects.Any(x => string.Equals(projectName, x, StringComparison.OrdinalIgnoreCase))) + { + buildContext.CakeContext.Warning("Project '{0}' should not be processed, does not exist as registered project", projectName); + return false; + } + if (buildContext.General.IsCiBuild) { // In CI builds, we always want to include all projects @@ -526,7 +588,9 @@ private static bool ShouldProcessProject(BuildContext buildContext, string proje // it can only work if they are not part of unit tests (but that should never happen) // if (buildContext.Tests.Items.Count == 0) // { - if (checkDeployment && !ShouldDeployProject(buildContext, projectName)) + if (checkDeployment && + !ShouldPackageProject(buildContext, projectName) && + !ShouldDeployProject(buildContext, projectName)) { buildContext.CakeContext.Warning("Project '{0}' should not be processed because this is not a CI build, does not contain tests and the project should not be deployed, removing from projects to process", projectName); return false; @@ -538,6 +602,39 @@ private static bool ShouldProcessProject(BuildContext buildContext, string proje //------------------------------------------------------------- +private static List GetProjectRuntimesIdentifiers(BuildContext buildContext, Cake.Core.IO.FilePath solutionOrProjectFileName, List runtimeIdentifiersToInvestigate) +{ + var projectFileContents = System.IO.File.ReadAllText(solutionOrProjectFileName.FullPath)?.ToLower(); + + var supportedRuntimeIdentifiers = new List(); + + foreach (var runtimeIdentifier in runtimeIdentifiersToInvestigate) + { + if (!string.IsNullOrWhiteSpace(runtimeIdentifier)) + { + if (!projectFileContents.Contains(runtimeIdentifier.ToLower())) + { + buildContext.CakeContext.Information("Project '{0}' does not support runtime identifier '{1}', removing from supported runtime identifiers list", solutionOrProjectFileName, runtimeIdentifier); + continue; + } + } + + supportedRuntimeIdentifiers.Add(runtimeIdentifier); + } + + if (supportedRuntimeIdentifiers.Count == 0) + { + buildContext.CakeContext.Information("Project '{0}' does not have any explicit runtime identifiers left, adding empty one as default", solutionOrProjectFileName); + + // Default + supportedRuntimeIdentifiers.Add(string.Empty); + } + + return supportedRuntimeIdentifiers; +} + +//------------------------------------------------------------- + private static bool ShouldBuildProject(BuildContext buildContext, string projectName) { // Allow the build server to configure this via "Build[ProjectName]" @@ -555,6 +652,34 @@ private static bool ShouldBuildProject(BuildContext buildContext, string project //------------------------------------------------------------- +private static bool ShouldPackageProject(BuildContext buildContext, string projectName) +{ + // Allow the build server to configure this via "Package[ProjectName]" + var slug = GetProjectSlug(projectName); + var keyToCheck = string.Format("Package{0}", slug); + + var shouldPackage = buildContext.BuildServer.GetVariableAsBool(keyToCheck, true); + + // If this is *only* a dependency, it should never be deployed + if (IsOnlyDependencyProject(buildContext, projectName)) + { + shouldPackage = false; + } + + if (shouldPackage && !ShouldProcessProject(buildContext, projectName, false)) + { + buildContext.CakeContext.Information($"Project '{projectName}' should not be processed, excluding it anyway"); + + shouldPackage = false; + } + + buildContext.CakeContext.Information($"Value for '{keyToCheck}': {shouldPackage}"); + + return shouldPackage; +} + +//------------------------------------------------------------- + private static bool ShouldDeployProject(BuildContext buildContext, string projectName) { // Allow the build server to configure this via "Deploy[ProjectName]" @@ -562,6 +687,13 @@ private static bool ShouldDeployProject(BuildContext buildContext, string projec var keyToCheck = string.Format("Deploy{0}", slug); var shouldDeploy = buildContext.BuildServer.GetVariableAsBool(keyToCheck, true); + + // If this is *only* a dependency, it should never be deployed + if (IsOnlyDependencyProject(buildContext, projectName)) + { + shouldDeploy = false; + } + if (shouldDeploy && !ShouldProcessProject(buildContext, projectName, false)) { buildContext.CakeContext.Information($"Project '{projectName}' should not be processed, excluding it anyway"); @@ -572,4 +704,84 @@ private static bool ShouldDeployProject(BuildContext buildContext, string projec buildContext.CakeContext.Information($"Value for '{keyToCheck}': {shouldDeploy}"); return shouldDeploy; +} + +//------------------------------------------------------------- + +private static bool IsOnlyDependencyProject(BuildContext buildContext, string projectName) +{ + buildContext.CakeContext.Information($"Checking if project '{projectName}' is a dependency only"); + + // If not in the dependencies list, we can stop checking + if (!buildContext.Dependencies.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is not in list of dependencies, assuming not dependency only"); + return false; + } + + if (buildContext.Components.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of components, assuming not dependency only"); + return false; + } + + if (buildContext.DockerImages.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of docker images, assuming not dependency only"); + return false; + } + + if (buildContext.GitHubPages.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of GitHub pages, assuming not dependency only"); + return false; + } + + if (buildContext.Templates.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of templates, assuming not dependency only"); + return false; + } + + if (buildContext.Tools.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of tools, assuming not dependency only"); + return false; + } + + if (buildContext.Uwp.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of UWP apps, assuming not dependency only"); + return false; + } + + if (buildContext.VsExtensions.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of VS extensions, assuming not dependency only"); + return false; + } + + if (buildContext.Web.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of web apps, assuming not dependency only"); + return false; + } + + if (buildContext.Wpf.Items.Contains(projectName)) + { + buildContext.CakeContext.Information($"Project is list of WPF apps, assuming not dependency only"); + return false; + } + + buildContext.CakeContext.Information($"Project '{projectName}' is a dependency only"); + + // It's in the dependencies list and not in any other list + return true; +} + +//------------------------------------------------------------- + +public static void Add(this Dictionary> dictionary, string project, params string[] projects) +{ + dictionary.Add(project, new List(projects)); } \ No newline at end of file diff --git a/deployment/cake/lib-logging.cake b/deployment/cake/lib-logging.cake index 7b319a1c..da08b224 100644 --- a/deployment/cake/lib-logging.cake +++ b/deployment/cake/lib-logging.cake @@ -8,7 +8,7 @@ /// // Temporary sets logging verbosity to Diagnostic. /// using(context.UseVerbosity(Verbosity.Diagnostic)) /// { -/// context.DotNetCoreBuild(project, settings); +/// context.DotNetBuild(project, settings); /// } /// /// @@ -24,7 +24,7 @@ public static VerbosityChanger UseVerbosity(this ICakeContext context, Verbosity /// // Temporary sets logging verbosity to Diagnostic. /// using(context.UseDiagnosticVerbosity()) /// { -/// context.DotNetCoreBuild(project, settings); +/// context.DotNetBuild(project, settings); /// } /// /// diff --git a/deployment/cake/lib-msbuild.cake b/deployment/cake/lib-msbuild.cake index d4cce716..35be5f3c 100644 --- a/deployment/cake/lib-msbuild.cake +++ b/deployment/cake/lib-msbuild.cake @@ -1,5 +1,5 @@ -#addin "nuget:?package=Cake.Issues&version=0.9.1" -#addin "nuget:?package=Cake.Issues.MsBuild&version=0.9.1" +#addin "nuget:?package=Cake.Issues&version=2.0.0" +#addin "nuget:?package=Cake.Issues.MsBuild&version=2.0.0" #tool "nuget:?package=MSBuild.Extension.Pack&version=1.9.1" @@ -23,15 +23,15 @@ private static void BuildSolution(BuildContext buildContext) NoLogo = true }; - //ConfigureMsBuild(buildContext, msBuildSettings, dependency); + //ConfigureMsBuild(buildContext, msBuildSettings, dependency, "build"); - RunMsBuild(buildContext, "Solution", solutionFileName, msBuildSettings); + RunMsBuild(buildContext, "Solution", solutionFileName, msBuildSettings, "build"); } //------------------------------------------------------------- private static void ConfigureMsBuild(BuildContext buildContext, MSBuildSettings msBuildSettings, - string projectName, string action = "build", bool? allowVsPrerelease = null) + string projectName, string action, bool? allowVsPrerelease = null) { var toolPath = GetVisualStudioPath(buildContext, allowVsPrerelease); if (!string.IsNullOrWhiteSpace(toolPath)) @@ -41,8 +41,38 @@ private static void ConfigureMsBuild(BuildContext buildContext, MSBuildSettings msBuildSettings.ToolPath = toolPath; } + // Note: we need to set OverridableOutputPath because we need to be able to respect + // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which + // are properties passed in using the command line) + var outputDirectory = GetProjectOutputDirectory(buildContext, projectName); + buildContext.CakeContext.Information("Output directory: '{0}'", outputDirectory); + msBuildSettings.WithProperty("OverridableOutputRootPath", buildContext.General.OutputRootDirectory); + + // GHK: 2022-05-25: Disabled overriding the (whole) output path since this caused all + // reference projects to be re-build again since this override is used for all projects, + // including project references + //msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); + + msBuildSettings.WithProperty("PackageOutputPath", buildContext.General.OutputRootDirectory); + + // Only optimize in release mode + if (!buildContext.General.IsLocalBuild) + { + buildContext.CakeContext.Information($"This is NOT a local build, disabling building of project references"); + + // Don't build project references (should already be built) + msBuildSettings.WithProperty("BuildProjectReferences", "false"); + + //InjectAssemblySearchPathsInProjectFile(buildContext, projectName, GetProjectFileName(buildContext, projectName)); + } + else + { + buildContext.CakeContext.Information($"This is a local build, disabling building of project references"); + } + // Continuous integration build - msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); + msBuildSettings.ContinuousIntegrationBuild = true; + //msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); // No NuGet restore (should already be done) msBuildSettings.WithProperty("ResolveNuGetPackages", "false"); @@ -81,8 +111,8 @@ private static void ConfigureMsBuild(BuildContext buildContext, MSBuildSettings //------------------------------------------------------------- -private static void ConfigureMsBuildForDotNetCore(BuildContext buildContext, DotNetCoreMSBuildSettings msBuildSettings, - string projectName, string action = "build", bool? allowVsPrerelease = null) +private static void ConfigureMsBuildForDotNet(BuildContext buildContext, DotNetMSBuildSettings msBuildSettings, + string projectName, string action, bool? allowVsPrerelease = null) { var toolPath = GetVisualStudioPath(buildContext, allowVsPrerelease); if (!string.IsNullOrWhiteSpace(toolPath)) @@ -92,8 +122,38 @@ private static void ConfigureMsBuildForDotNetCore(BuildContext buildContext, Dot msBuildSettings.ToolPath = toolPath; } + // Note: we need to set OverridableOutputPath because we need to be able to respect + // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which + // are properties passed in using the command line) + var outputDirectory = GetProjectOutputDirectory(buildContext, projectName); + buildContext.CakeContext.Information("Output directory: '{0}'", outputDirectory); + msBuildSettings.WithProperty("OverridableOutputRootPath", buildContext.General.OutputRootDirectory); + + // GHK: 2022-05-25: Disabled overriding the (whole) output path since this caused all + // reference projects to be re-build again since this override is used for all projects, + // including project references + //msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); + + msBuildSettings.WithProperty("PackageOutputPath", buildContext.General.OutputRootDirectory); + + // Only optimize in release mode + if (!buildContext.General.IsLocalBuild) + { + buildContext.CakeContext.Information($"This is NOT a local build, disabling building of project references"); + + // Don't build project references (should already be built) + msBuildSettings.WithProperty("BuildProjectReferences", "false"); + + //InjectAssemblySearchPathsInProjectFile(buildContext, projectName, GetProjectFileName(buildContext, projectName)); + } + else + { + buildContext.CakeContext.Information($"This is a local build, disabling building of project references"); + } + // Continuous integration build - msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); + msBuildSettings.ContinuousIntegrationBuild = true; + //msBuildSettings.WithProperty("ContinuousIntegrationBuild", "true"); // No NuGet restore (should already be done) msBuildSettings.WithProperty("ResolveNuGetPackages", "false"); @@ -122,12 +182,12 @@ private static void ConfigureMsBuildForDotNetCore(BuildContext buildContext, Dot }); // Enable for bin logging - //msBuildSettings.BinaryLogger = new MSBuildBinaryLogSettings - //{ - // Enabled = true, - // Imports = MSBuildBinaryLogImports.Embed, - // FileName = System.IO.Path.Combine(OutputRootDirectory, string.Format(@"MsBuild_{0}_{1}.binlog", projectName, action)) - //}; + msBuildSettings.BinaryLogger = new MSBuildBinaryLoggerSettings + { + Enabled = true, + Imports = MSBuildBinaryLoggerImports.Embed, + FileName = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, string.Format(@"MsBuild_{0}_{1}.binlog", projectName, action)) + }; // Note: this only works for direct .net core msbuild usage, not when this is // being wrapped in a tool (such as 'dotnet pack') @@ -139,7 +199,7 @@ private static void ConfigureMsBuildForDotNetCore(BuildContext buildContext, Dot //------------------------------------------------------------- -private static void RunMsBuild(BuildContext buildContext, string projectName, string projectFileName, MSBuildSettings msBuildSettings) +private static void RunMsBuild(BuildContext buildContext, string projectName, string projectFileName, MSBuildSettings msBuildSettings, string action) { // IMPORTANT NOTE --- READ <============================================= // @@ -149,8 +209,10 @@ private static void RunMsBuild(BuildContext buildContext, string projectName, st // // IMPORTANT NOTE --- READ <============================================= + var totalStopwatch = Stopwatch.StartNew(); + var buildStopwatch = Stopwatch.StartNew(); + // Enforce additional logging for issues - var action = "build"; //var logPath = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, string.Format(@"MsBuild_{0}_{1}_log.binlog", projectName, action)); buildContext.CakeContext.CreateDirectory(buildContext.General.OutputRootDirectory); @@ -162,8 +224,11 @@ private static void RunMsBuild(BuildContext buildContext, string projectName, st var failBuild = false; try - { - buildContext.CakeContext.MSBuild(projectFileName, msBuildSettings); + { + // using (buildContext.CakeContext.UseDiagnosticVerbosity()) + // { + buildContext.CakeContext.MSBuild(projectFileName, msBuildSettings); + //} } catch (System.Exception) { @@ -172,9 +237,13 @@ private static void RunMsBuild(BuildContext buildContext, string projectName, st } buildContext.CakeContext.Information(string.Empty); - buildContext.CakeContext.Information($"Done building project, investigating potential issues using '{logPath}'"); + buildContext.CakeContext.Information($"Done {action}ing project, took '{buildStopwatch.Elapsed}'"); + buildContext.CakeContext.Information(string.Empty); + buildContext.CakeContext.Information($"Investigating potential issues using '{logPath}'"); buildContext.CakeContext.Information(string.Empty); + var investigationStopwatch = Stopwatch.StartNew(); + var issuesContext = buildContext.CakeContext.MsBuildIssuesFromFilePath(logPath, buildContext.CakeContext.MsBuildXmlFileLoggerFormat()); //var issuesContext = buildContext.CakeContext.MsBuildIssuesFromFilePath(logPath, buildContext.CakeContext.MsBuildBinaryLogFileFormat()); @@ -216,11 +285,16 @@ private static void RunMsBuild(BuildContext buildContext, string projectName, st } } + buildContext.CakeContext.Information(string.Empty); + buildContext.CakeContext.Information($"Done investigating project, took '{investigationStopwatch.Elapsed}'"); + buildContext.CakeContext.Information($"Total msbuild ({action} + investigation) took '{totalStopwatch.Elapsed}'"); + buildContext.CakeContext.Information(string.Empty); + if (failBuild) { buildContext.CakeContext.Information(string.Empty); - throw new Exception($"Build failed for project '{projectName}'"); + throw new Exception($"{action} failed for project '{projectName}'"); } } @@ -248,42 +322,65 @@ private static string GetVisualStudioDirectory(BuildContext buildContext, bool? { // TODO: Support different editions (e.g. Professional, Enterprise, Community, etc) + // Force 64-bit, even when running as 32-bit process + var programFilesx64 = Environment.ExpandEnvironmentVariables("%ProgramW6432%"); + var programFilesx86 = Environment.ExpandEnvironmentVariables("%ProgramFiles(x86)%"); + + var prereleasePaths = new List>(new [] + { + new KeyValuePair("Visual Studio 2022 Preview", $@"{programFilesx64}\Microsoft Visual Studio\2022\Preview\"), + new KeyValuePair("Visual Studio 2019 Preview", $@"{programFilesx86}\Microsoft Visual Studio\2019\Preview\"), + }); + + var normalPaths = new List> (new [] + { + new KeyValuePair("Visual Studio 2022 Enterprise", $@"{programFilesx64}\Microsoft Visual Studio\2022\Enterprise\"), + new KeyValuePair("Visual Studio 2022 Professional", $@"{programFilesx64}\Microsoft Visual Studio\2022\Professional\"), + new KeyValuePair("Visual Studio 2022 Community", $@"{programFilesx64}\Microsoft Visual Studio\2022\Community\"), + new KeyValuePair("Visual Studio 2019 Enterprise", $@"{programFilesx86}\Microsoft Visual Studio\2019\Enterprise\"), + new KeyValuePair("Visual Studio 2019 Professional", $@"{programFilesx86}\Microsoft Visual Studio\2019\Professional\"), + new KeyValuePair("Visual Studio 2019 Community", $@"{programFilesx86}\Microsoft Visual Studio\2019\Community\"), + }); + + // Prerelease paths if ((allowVsPrerelease ?? true) && buildContext.General.UseVisualStudioPrerelease) { - buildContext.CakeContext.Debug("Checking for installation of Visual Studio 2019 preview"); + buildContext.CakeContext.Debug("Checking for installation of Visual Studio (preview)"); - var pathFor2019Preview = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\Microsoft Visual Studio\2019\Preview\"; - if (System.IO.Directory.Exists(pathFor2019Preview)) + foreach (var prereleasePath in prereleasePaths) { - // Note: SonarQube supports VS 2019 now - //buildContext.CakeContext.Information("Using Visual Studio 2019 preview, note that SonarQube will be disabled since it's not (yet) compatible with VS2019"); - //buildContext.General.SonarQube.IsDisabled = true; - return pathFor2019Preview; + if (System.IO.Directory.Exists(prereleasePath.Value)) + { + buildContext.CakeContext.Debug($"Found {prereleasePath.Key}"); + + return prereleasePath.Value; + } } } - - buildContext.CakeContext.Debug("Checking for installation of Visual Studio 2019"); - var pathFor2019Enterprise = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\Microsoft Visual Studio\2019\Enterprise\"; - if (System.IO.Directory.Exists(pathFor2019Enterprise)) + buildContext.CakeContext.Debug("Checking for installation of Visual Studio (non-preview)"); + + // Normal paths + foreach (var normalPath in normalPaths) { - buildContext.CakeContext.Information("Using Visual Studio 2019 Enterprise"); - return pathFor2019Enterprise; - } + if (System.IO.Directory.Exists(normalPath.Value)) + { + buildContext.CakeContext.Debug($"Found {normalPath.Key}"); - var pathFor2019Professional = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\Microsoft Visual Studio\2019\Professional\"; - if (System.IO.Directory.Exists(pathFor2019Professional)) - { - buildContext.CakeContext.Information("Using Visual Studio 2019 Professional"); - return pathFor2019Professional; + return normalPath.Value; + } } - - var pathFor2019Community = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\Microsoft Visual Studio\2019\Community\"; - if (System.IO.Directory.Exists(pathFor2019Community)) + + // Fallback in case someone *only* has prerelease + foreach (var prereleasePath in prereleasePaths) { - buildContext.CakeContext.Information("Using Visual Studio 2019 CE"); - return pathFor2019Community; - } + if (System.IO.Directory.Exists(prereleasePath.Value)) + { + buildContext.CakeContext.Information($"Only Visual Studio preview is available, using {prereleasePath.Key}"); + + return prereleasePath.Value; + } + } // Failed return null; @@ -296,6 +393,8 @@ private static string GetVisualStudioPath(BuildContext buildContext, bool? allow var potentialPaths = new [] { @"MSBuild\Current\Bin\msbuild.exe", + @"MSBuild\17.0\Bin\msbuild.exe", + @"MSBuild\16.0\Bin\msbuild.exe", @"MSBuild\15.0\Bin\msbuild.exe" }; @@ -312,3 +411,57 @@ private static string GetVisualStudioPath(BuildContext buildContext, bool? allow throw new Exception("Could not find the path to Visual Studio (msbuild.exe)"); } + +//------------------------------------------------------------- + +private static void InjectAssemblySearchPathsInProjectFile(BuildContext buildContext, string projectName, string projectFileName) +{ + try + { + // Allow this project to find any other projects that we have built (since we disabled + // building of project dependencies) + var assemblySearchPaths = new List(); + var separator = System.IO.Path.DirectorySeparatorChar.ToString(); + + foreach (var project in buildContext.AllProjects) + { + var projectOutputDirectory = GetProjectOutputDirectory(buildContext, project); + assemblySearchPaths.Add(projectOutputDirectory); + } + + if (assemblySearchPaths.Count == 0) + { + buildContext.CakeContext.Information("No assembly search paths found to inject"); + return; + } + + // For SourceLink to work, the .csproj should contain something like this: + // + var projectFileContents = System.IO.File.ReadAllText(projectFileName); + if (projectFileContents.Contains("AssemblySearchPaths")) + { + buildContext.CakeContext.Information("Assembly search paths is already added to the project file"); + return; + } + + buildContext.CakeContext.Information("Injecting assembly search paths into project file"); + + var xmlDocument = XDocument.Parse(projectFileContents); + var projectElement = xmlDocument.Root; + + // Item group with package reference + var propertyGroupElement = new XElement("PropertyGroup"); + var assemblySearchPathsElement = new XElement("AssemblySearchPaths"); + + assemblySearchPathsElement.Value = $"$(AssemblySearchPaths);{string.Join(";", assemblySearchPaths)}"; + + propertyGroupElement.Add(assemblySearchPathsElement); + projectElement.Add(propertyGroupElement); + + xmlDocument.Save(projectFileName); + } + catch (Exception ex) + { + buildContext.CakeContext.Error($"Failed to process assembly search paths for project '{projectFileName}': {ex.Message}"); + } +} \ No newline at end of file diff --git a/deployment/cake/lib-nuget.cake b/deployment/cake/lib-nuget.cake index 4b5c2b4f..82627022 100644 --- a/deployment/cake/lib-nuget.cake +++ b/deployment/cake/lib-nuget.cake @@ -53,30 +53,42 @@ private static void RestoreNuGetPackages(BuildContext buildContext, Cake.Core.IO buildContext.CakeContext.LogSeparator("Restoring packages for '{0}'", solutionOrProjectFileName); var sources = SplitSeparatedList(buildContext.General.NuGet.PackageSources, ';'); + var runtimeIdentifiers = new List(new [] { "win-x64", "browser-wasm" }); - RestoreNuGetPackagesUsingNuGet(buildContext, solutionOrProjectFileName, sources); - RestoreNuGetPackagesUsingDotnetRestore(buildContext, solutionOrProjectFileName, sources, runtimeIdentifiers); + var supportedRuntimeIdentifiers = GetProjectRuntimesIdentifiers(buildContext, solutionOrProjectFileName, runtimeIdentifiers); + + RestoreNuGetPackagesUsingNuGet(buildContext, solutionOrProjectFileName, sources, supportedRuntimeIdentifiers); + RestoreNuGetPackagesUsingDotnetRestore(buildContext, solutionOrProjectFileName, sources, supportedRuntimeIdentifiers); } //------------------------------------------------------------- -private static void RestoreNuGetPackagesUsingNuGet(BuildContext buildContext, Cake.Core.IO.FilePath solutionOrProjectFileName, List sources) +private static void RestoreNuGetPackagesUsingNuGet(BuildContext buildContext, Cake.Core.IO.FilePath solutionOrProjectFileName, List sources, List runtimeIdentifiers) { + if (!buildContext.General.NuGet.RestoreUsingNuGet) + { + return; + } + buildContext.CakeContext.LogSeparator("Restoring packages for '{0}' using 'NuGet'", solutionOrProjectFileName); + // No need to deal with runtime identifiers + try { var nuGetRestoreSettings = new NuGetRestoreSettings { DisableParallelProcessing = false, NoCache = false, + NonInteractive = true, + RequireConsent = false }; - + if (sources.Count > 0) { nuGetRestoreSettings.Source = sources; @@ -94,52 +106,34 @@ private static void RestoreNuGetPackagesUsingNuGet(BuildContext buildContext, Ca private static void RestoreNuGetPackagesUsingDotnetRestore(BuildContext buildContext, Cake.Core.IO.FilePath solutionOrProjectFileName, List sources, List runtimeIdentifiers) { - buildContext.CakeContext.LogSeparator("Restoring packages for '{0}' using 'dotnet restore'", solutionOrProjectFileName); - - var projectFileContents = System.IO.File.ReadAllText(solutionOrProjectFileName.FullPath)?.ToLower(); - - var supportedRuntimeIdentifiers = new List(); - - foreach (var runtimeIdentifier in runtimeIdentifiers) + if (!buildContext.General.NuGet.RestoreUsingDotNetRestore) { - if (!string.IsNullOrWhiteSpace(runtimeIdentifier)) - { - if (!projectFileContents.Contains(runtimeIdentifier.ToLower())) - { - buildContext.CakeContext.Information("Project '{0}' does not support runtime identifier '{1}', skipping restore for this runtime identifier", solutionOrProjectFileName, runtimeIdentifier); - continue; - } - } - - supportedRuntimeIdentifiers.Add(runtimeIdentifier); - } - - if (supportedRuntimeIdentifiers.Count == 0) - { - // Default - supportedRuntimeIdentifiers.Add(string.Empty); + return; } - foreach (var runtimeIdentifier in supportedRuntimeIdentifiers) + buildContext.CakeContext.LogSeparator("Restoring packages for '{0}' using 'dotnet restore'", solutionOrProjectFileName); + + foreach (var runtimeIdentifier in runtimeIdentifiers) { try { buildContext.CakeContext.LogSeparator("Restoring packages for '{0}' using 'dotnet restore' using runtime identifier '{1}'", solutionOrProjectFileName, runtimeIdentifier); - var restoreSettings = new DotNetCoreRestoreSettings + var restoreSettings = new DotNetRestoreSettings { DisableParallel = false, Force = false, ForceEvaluate = false, IgnoreFailedSources = true, NoCache = false, - NoDependencies = false, // use true to speed up things - Verbosity = DotNetCoreVerbosity.Normal + NoDependencies = buildContext.General.NuGet.NoDependencies, // use true to speed up things + Verbosity = DotNetVerbosity.Normal }; if (!string.IsNullOrWhiteSpace(runtimeIdentifier)) { - // This is a explicit supported runtime identifier, force re-evaluation + buildContext.CakeContext.Information("Project restore uses explicit runtime identifier, forcing re-evaluation"); + restoreSettings.Force = true; restoreSettings.ForceEvaluate = true; restoreSettings.Runtime = runtimeIdentifier; @@ -152,7 +146,7 @@ private static void RestoreNuGetPackagesUsingDotnetRestore(BuildContext buildCon using (buildContext.CakeContext.UseDiagnosticVerbosity()) { - buildContext.CakeContext.DotNetCoreRestore(solutionOrProjectFileName.FullPath, restoreSettings); + buildContext.CakeContext.DotNetRestore(solutionOrProjectFileName.FullPath, restoreSettings); } } catch (Exception) diff --git a/deployment/cake/lib-octopusdeploy.cake b/deployment/cake/lib-octopusdeploy.cake index af1cd567..e1a2fd1f 100644 --- a/deployment/cake/lib-octopusdeploy.cake +++ b/deployment/cake/lib-octopusdeploy.cake @@ -1,4 +1,4 @@ -#tool "nuget:?package=OctopusTools&version=7.4.3104" +#tool "nuget:?package=OctopusTools&version=9.1.7" public class OctopusDeployIntegration : IntegrationBase { diff --git a/deployment/cake/lib-signing.cake b/deployment/cake/lib-signing.cake index a719f2ee..ba334baf 100644 --- a/deployment/cake/lib-signing.cake +++ b/deployment/cake/lib-signing.cake @@ -2,6 +2,26 @@ private static string _signToolFileName; //------------------------------------------------------------- +public static bool ShouldSignImmediately(BuildContext buildContext, string projectName) +{ + if (buildContext.General.IsLocalBuild || + buildContext.General.IsCiBuild) + { + // Never code-sign local or ci builds + return false; + } + + if (buildContext.CodeSigning.ProjectsToSignImmediately.Contains(projectName)) + { + buildContext.CakeContext.Information($"Immediately code signing '{projectName}' files"); + return true; + } + + return false; +} + +//------------------------------------------------------------- + public static void SignFiles(BuildContext buildContext, string signToolCommand, IEnumerable fileNames, string additionalCommandLineArguments = null) { if (fileNames.Any()) @@ -52,6 +72,11 @@ public static void SignFile(BuildContext buildContext, string signToolCommand, s _signToolFileName = FindSignToolFileName(buildContext); } + if (string.IsNullOrWhiteSpace(_signToolFileName)) + { + throw new InvalidOperationException("Cannot find signtool.exe, make sure to install a Windows Development Kit"); + } + buildContext.CakeContext.Information(string.Empty); // Retry mechanism, signing with timestamping is not as reliable as we thought @@ -133,4 +158,4 @@ public static string FindSignToolFileName(BuildContext buildContext) } return null; -} \ No newline at end of file +} diff --git a/deployment/cake/lib-sourcelink.cake b/deployment/cake/lib-sourcelink.cake index 52142bcb..474c3937 100644 --- a/deployment/cake/lib-sourcelink.cake +++ b/deployment/cake/lib-sourcelink.cake @@ -1,4 +1,4 @@ -public static bool IsSourceLinkSupported(BuildContext buildContext, string projectFileName) +public static bool IsSourceLinkSupported(BuildContext buildContext, string projectName, string projectFileName) { if (buildContext.General.SourceLink.IsDisabled) { @@ -21,6 +21,12 @@ public static bool IsSourceLinkSupported(BuildContext buildContext, string proje return false; } + // Is this a test project? + if (buildContext.Tests.Items.Contains(projectName)) + { + return false; + } + // Only support when running a real build, e.g. ot for 'Package' only if (!buildContext.General.Target.ToLower().Contains("build")) { @@ -32,62 +38,69 @@ public static bool IsSourceLinkSupported(BuildContext buildContext, string proje //------------------------------------------------------------- -public static void InjectSourceLinkInProjectFile(BuildContext buildContext, string projectFileName) +public static void InjectSourceLinkInProjectFile(BuildContext buildContext, string projectName, string projectFileName) { - // Only support C# projects - if (!IsSourceLinkSupported(buildContext, projectFileName)) + try { - return; + // Only support C# projects + if (!IsSourceLinkSupported(buildContext, projectName, projectFileName)) + { + return; + } + + // For SourceLink to work, the .csproj should contain something like this: + // + var projectFileContents = System.IO.File.ReadAllText(projectFileName); + if (projectFileContents.Contains("Microsoft.SourceLink.GitHub")) + { + return; + } + + buildContext.CakeContext.Warning("No SourceLink reference found, automatically injecting SourceLink package reference now"); + + //const string MSBuildNS = (XNamespace) "http://schemas.microsoft.com/developer/msbuild/2003"; + + var xmlDocument = XDocument.Parse(projectFileContents); + var projectElement = xmlDocument.Root; + + // Item group with package reference + var referencesItemGroup = new XElement("ItemGroup"); + var sourceLinkPackageReference = new XElement("PackageReference"); + sourceLinkPackageReference.Add(new XAttribute("Include", "Microsoft.SourceLink.GitHub")); + sourceLinkPackageReference.Add(new XAttribute("Version", "1.1.1")); + sourceLinkPackageReference.Add(new XAttribute("PrivateAssets", "all")); + + referencesItemGroup.Add(sourceLinkPackageReference); + projectElement.Add(referencesItemGroup); + + // Item group with source root + // + var sourceRootItemGroup = new XElement("ItemGroup"); + var sourceRoot = new XElement("SourceRoot"); + + // Required to end with a \ + var sourceRootValue = buildContext.General.RootDirectory; + var directorySeparator = System.IO.Path.DirectorySeparatorChar.ToString(); + if (!sourceRootValue.EndsWith(directorySeparator)) + { + sourceRootValue += directorySeparator; + }; + + sourceRoot.Add(new XAttribute("Include", sourceRootValue)); + sourceRoot.Add(new XAttribute("RepositoryUrl", buildContext.General.Repository.Url)); + + // Note: since we are not allowing source control manager queries (we don't want to require a .git directory), + // we must specify the additional information below + sourceRoot.Add(new XAttribute("SourceControl", "git")); + sourceRoot.Add(new XAttribute("RevisionId", buildContext.General.Repository.CommitId)); + + sourceRootItemGroup.Add(sourceRoot); + projectElement.Add(sourceRootItemGroup); + + xmlDocument.Save(projectFileName); } - - // For SourceLink to work, the .csproj should contain something like this: - // - var projectFileContents = System.IO.File.ReadAllText(projectFileName); - if (projectFileContents.Contains("Microsoft.SourceLink.GitHub")) + catch (Exception ex) { - return; + buildContext.CakeContext.Error($"Failed to process source link for project '{projectFileName}': {ex.Message}"); } - - buildContext.CakeContext.Warning("No SourceLink reference found, automatically injecting SourceLink package reference now"); - - //const string MSBuildNS = (XNamespace) "http://schemas.microsoft.com/developer/msbuild/2003"; - - var xmlDocument = XDocument.Parse(projectFileContents); - var projectElement = xmlDocument.Root; - - // Item group with package reference - var referencesItemGroup = new XElement("ItemGroup"); - var sourceLinkPackageReference = new XElement("PackageReference"); - sourceLinkPackageReference.Add(new XAttribute("Include", "Microsoft.SourceLink.GitHub")); - sourceLinkPackageReference.Add(new XAttribute("Version", "1.0.0")); - sourceLinkPackageReference.Add(new XAttribute("PrivateAssets", "all")); - - referencesItemGroup.Add(sourceLinkPackageReference); - projectElement.Add(referencesItemGroup); - - // Item group with source root - // - var sourceRootItemGroup = new XElement("ItemGroup"); - var sourceRoot = new XElement("SourceRoot"); - - // Required to end with a \ - var sourceRootValue = buildContext.General.RootDirectory; - var directorySeparator = System.IO.Path.DirectorySeparatorChar.ToString(); - if (!sourceRootValue.EndsWith(directorySeparator)) - { - sourceRootValue += directorySeparator; - }; - - sourceRoot.Add(new XAttribute("Include", sourceRootValue)); - sourceRoot.Add(new XAttribute("RepositoryUrl", buildContext.General.Repository.Url)); - - // Note: since we are not allowing source control manager queries (we don't want to require a .git directory), - // we must specify the additional information below - sourceRoot.Add(new XAttribute("SourceControl", "git")); - sourceRoot.Add(new XAttribute("RevisionId", buildContext.General.Repository.CommitId)); - - sourceRootItemGroup.Add(sourceRoot); - projectElement.Add(sourceRootItemGroup); - - xmlDocument.Save(projectFileName); } \ No newline at end of file diff --git a/deployment/cake/notifications-msteams.cake b/deployment/cake/notifications-msteams.cake index 9d514a70..0be4310a 100644 --- a/deployment/cake/notifications-msteams.cake +++ b/deployment/cake/notifications-msteams.cake @@ -1,4 +1,4 @@ -#addin "nuget:?package=Cake.MicrosoftTeams&version=1.0.0" +#addin "nuget:?package=Cake.MicrosoftTeams&version=2.0.0" //------------------------------------------------------------- diff --git a/deployment/cake/sourcecontrol-github.cake b/deployment/cake/sourcecontrol-github.cake index 1f912637..2cb1d61e 100644 --- a/deployment/cake/sourcecontrol-github.cake +++ b/deployment/cake/sourcecontrol-github.cake @@ -1,5 +1,5 @@ #addin "nuget:?package=Cake.GitHub&version=0.1.0" -#addin "nuget:?package=Octokit&version=0.49.0" +#addin "nuget:?package=Octokit&version=5.0.0" //------------------------------------------------------------- @@ -54,11 +54,16 @@ public class GitHubSourceControl : ISourceControl private void UpdateStatus(GitHubStatusState state, string context, string description) { + // Disabled for now + return; + if (!IsAvailable) { return; } + BuildContext.CakeContext.Information("Updating GitHub status to '{0}' | '{1}'", state, description); + var commitSha = BuildContext.General.Repository.CommitId; BuildContext.CakeContext.GitHubStatus(UserName, ApiKey, OwnerName, ProjectName, commitSha, new GitHubStatusSettings diff --git a/deployment/cake/sourcecontrol.cake b/deployment/cake/sourcecontrol.cake index 4d9ad9f3..9c7b5279 100644 --- a/deployment/cake/sourcecontrol.cake +++ b/deployment/cake/sourcecontrol.cake @@ -24,7 +24,7 @@ public class SourceControlIntegration : IntegrationBase public async Task MarkBuildAsPendingAsync(string context, string description = null) { - BuildContext.CakeContext.LogSeparator("Marking build as pending"); + BuildContext.CakeContext.LogSeparator($"Marking build as pending: '{description ?? string.Empty}'"); context = context ?? "default"; description = description ?? "Build pending"; @@ -44,7 +44,7 @@ public class SourceControlIntegration : IntegrationBase public async Task MarkBuildAsFailedAsync(string context, string description = null) { - BuildContext.CakeContext.LogSeparator("Marking build as failed"); + BuildContext.CakeContext.LogSeparator($"Marking build as failed: '{description ?? string.Empty}'"); context = context ?? "default"; description = description ?? "Build failed"; @@ -64,7 +64,7 @@ public class SourceControlIntegration : IntegrationBase public async Task MarkBuildAsSucceededAsync(string context, string description = null) { - BuildContext.CakeContext.LogSeparator("Marking build as succeeded"); + BuildContext.CakeContext.LogSeparator($"Marking build as succeeded: '{description ?? string.Empty}'"); context = context ?? "default"; description = description ?? "Build succeeded"; diff --git a/deployment/cake/tasks.cake b/deployment/cake/tasks.cake index 9add3145..abfdd871 100644 --- a/deployment/cake/tasks.cake +++ b/deployment/cake/tasks.cake @@ -14,6 +14,7 @@ #l "apps-uwp-tasks.cake" #l "apps-web-tasks.cake" #l "apps-wpf-tasks.cake" +#l "codesigning-tasks.cake" #l "components-tasks.cake" #l "dependencies-tasks.cake" #l "tools-tasks.cake" @@ -23,16 +24,19 @@ #l "tests.cake" #l "templates-tasks.cake" -#addin "nuget:?package=Cake.FileHelpers&version=3.3.0" -#addin "nuget:?package=Cake.Sonar&version=1.1.25" +#addin "nuget:?package=Cake.FileHelpers&version=6.0.0" +#addin "nuget:?package=Cake.Sonar&version=1.1.31" #addin "nuget:?package=MagicChunks&version=2.0.0.119" -#addin "nuget:?package=Newtonsoft.Json&version=12.0.3" -#addin "nuget:?package=System.Net.Http&version=4.3.4" +#addin "nuget:?package=Newtonsoft.Json&version=13.0.2" -// Note: the SonarQube tool must be installed as a global .NET tool: +// Note: the SonarQube tool must be installed as a global .NET tool. If you are getting issues like this: +// +// The SonarScanner for MSBuild integration failed: [...] was unable to collect the required information about your projects. +// +// It probably means the tool is not correctly installed. // `dotnet tool install --global dotnet-sonarscanner --ignore-failed-sources` //#tool "nuget:?package=MSBuild.SonarQube.Runner.Tool&version=4.8.0" -#tool "nuget:?package=dotnet-sonarscanner&version=5.0.4" +#tool "nuget:?package=dotnet-sonarscanner&version=5.11.0" //------------------------------------------------------------- // BACKWARDS COMPATIBILITY CODE - START @@ -73,6 +77,7 @@ public class BuildContext : BuildContextBase { Processors = new List(); AllProjects = new List(); + RegisteredProjects = new List(); Variables = new Dictionary(); } @@ -92,6 +97,7 @@ public class BuildContext : BuildContextBase public GeneralContext General { get; set; } public TestsContext Tests { get; set; } + public CodeSigningContext CodeSigning { get; set; } public ComponentsContext Components { get; set; } public DependenciesContext Dependencies { get; set; } public DockerImagesContext DockerImages { get; set; } @@ -104,6 +110,7 @@ public class BuildContext : BuildContextBase public WpfContext Wpf { get; set; } public List AllProjects { get; private set; } + public List RegisteredProjects { get; private set; } protected override void ValidateContext() { @@ -131,12 +138,14 @@ Setup(setupContext => // Important: build server first so other integrations can read values from config buildContext.BuildServer = GetBuildServerIntegration(); + buildContext.BuildServer.SetBuildContext(buildContext); setupContext.LogSeparator("Creating build context"); buildContext.General = InitializeGeneralContext(buildContext, buildContext); buildContext.Tests = InitializeTestsContext(buildContext, buildContext); + buildContext.CodeSigning = InitializeCodeSigningContext(buildContext, buildContext); buildContext.Components = InitializeComponentsContext(buildContext, buildContext); buildContext.Dependencies = InitializeDependenciesContext(buildContext, buildContext); buildContext.DockerImages = InitializeDockerImagesContext(buildContext, buildContext); @@ -148,18 +157,6 @@ Setup(setupContext => buildContext.Web = InitializeWebContext(buildContext, buildContext); buildContext.Wpf = InitializeWpfContext(buildContext, buildContext); - // All projects, but dependencies first & tests last - buildContext.AllProjects.AddRange(buildContext.Dependencies.Items); - buildContext.AllProjects.AddRange(buildContext.Components.Items); - buildContext.AllProjects.AddRange(buildContext.DockerImages.Items); - buildContext.AllProjects.AddRange(buildContext.GitHubPages.Items); - buildContext.AllProjects.AddRange(buildContext.Tools.Items); - buildContext.AllProjects.AddRange(buildContext.Uwp.Items); - buildContext.AllProjects.AddRange(buildContext.VsExtensions.Items); - buildContext.AllProjects.AddRange(buildContext.Web.Items); - buildContext.AllProjects.AddRange(buildContext.Wpf.Items); - buildContext.AllProjects.AddRange(buildContext.Tests.Items); - // Other integrations last buildContext.IssueTracker = new IssueTrackerIntegration(buildContext); buildContext.Installer = new InstallerIntegration(buildContext); @@ -184,6 +181,7 @@ Setup(setupContext => buildContext.Processors.Add(new VsExtensionsProcessor(buildContext)); buildContext.Processors.Add(new WebProcessor(buildContext)); buildContext.Processors.Add(new WpfProcessor(buildContext)); + // !!! Note: we add test projects *after* preparing all the other processors, see Prepare task !!! setupContext.LogSeparator("Registering variables for templates"); @@ -204,6 +202,8 @@ Setup(setupContext => Task("Initialize") .Does(async buildContext => { + await buildContext.BuildServer.BeforeInitializeAsync(); + buildContext.CakeContext.LogSeparator("Writing special values back to build server"); var displayVersion = buildContext.General.Version.FullSemVer; @@ -212,7 +212,7 @@ Task("Initialize") displayVersion += " ci"; } - buildContext.BuildServer.SetVersion(displayVersion); + await buildContext.BuildServer.SetVersionAsync(displayVersion); var variablesToUpdate = new Dictionary(); variablesToUpdate["channel"] = buildContext.Wpf.Channel; @@ -229,8 +229,10 @@ Task("Initialize") foreach (var variableToUpdate in variablesToUpdate) { - buildContext.BuildServer.SetVariable(variableToUpdate.Key, variableToUpdate.Value); + await buildContext.BuildServer.SetVariableAsync(variableToUpdate.Key, variableToUpdate.Value); } + + await buildContext.BuildServer.AfterInitializeAsync(); }); //------------------------------------------------------------- @@ -238,10 +240,91 @@ Task("Initialize") Task("Prepare") .Does(async buildContext => { + // Add all projects to registered projects + buildContext.RegisteredProjects.AddRange(buildContext.Components.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Dependencies.Items); + buildContext.RegisteredProjects.AddRange(buildContext.DockerImages.Items); + buildContext.RegisteredProjects.AddRange(buildContext.GitHubPages.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Tests.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Tools.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Uwp.Items); + buildContext.RegisteredProjects.AddRange(buildContext.VsExtensions.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Web.Items); + buildContext.RegisteredProjects.AddRange(buildContext.Wpf.Items); + + await buildContext.BuildServer.BeforePrepareAsync(); + foreach (var processor in buildContext.Processors) { + if (processor is DependenciesProcessor) + { + // Process later + continue; + } + await processor.PrepareAsync(); } + + // Now add all projects, but dependencies first & tests last, which will be added at the end + buildContext.AllProjects.AddRange(buildContext.Components.Items); + buildContext.AllProjects.AddRange(buildContext.DockerImages.Items); + buildContext.AllProjects.AddRange(buildContext.GitHubPages.Items); + buildContext.AllProjects.AddRange(buildContext.Tools.Items); + buildContext.AllProjects.AddRange(buildContext.Uwp.Items); + buildContext.AllProjects.AddRange(buildContext.VsExtensions.Items); + buildContext.AllProjects.AddRange(buildContext.Web.Items); + buildContext.AllProjects.AddRange(buildContext.Wpf.Items); + + buildContext.CakeContext.LogSeparator("Final check which test projects should be included (1/2)"); + + // Once we know all the projects that will be built, we calculate which + // test projects need to be built as well + + var testProcessor = new TestProcessor(buildContext); + await testProcessor.PrepareAsync(); + buildContext.Processors.Add(testProcessor); + + buildContext.CakeContext.Information(string.Empty); + buildContext.CakeContext.Information($"Found '{buildContext.Tests.Items.Count}' test projects"); + + foreach (var test in buildContext.Tests.Items) + { + buildContext.CakeContext.Information($" - {test}"); + } + + buildContext.AllProjects.AddRange(buildContext.Tests.Items); + + buildContext.CakeContext.LogSeparator("Final check which dependencies should be included (2/2)"); + + // Now we really really determined all projects to build, we can check the dependencies + var dependenciesProcessor = (DependenciesProcessor)buildContext.Processors.First(x => x is DependenciesProcessor); + await dependenciesProcessor.PrepareAsync(); + + buildContext.CakeContext.Information(string.Empty); + buildContext.CakeContext.Information($"Found '{buildContext.Dependencies.Items.Count}' dependencies"); + + foreach (var dependency in buildContext.Dependencies.Items) + { + buildContext.CakeContext.Information($" - {dependency}"); + } + + // Add to the front, these are dependencies after all + buildContext.AllProjects.InsertRange(0, buildContext.Dependencies.Items); + + // Now we have the full collection, distinct + var allProjects = buildContext.AllProjects.ToArray(); + + buildContext.AllProjects.Clear(); + buildContext.AllProjects.AddRange(allProjects.Distinct()); + + buildContext.CakeContext.LogSeparator("Final projects to process"); + + foreach (var item in buildContext.AllProjects.ToList()) + { + buildContext.CakeContext.Information($"- {item}"); + } + + await buildContext.BuildServer.AfterPrepareAsync(); }); //------------------------------------------------------------- @@ -250,12 +333,16 @@ Task("UpdateInfo") .IsDependentOn("Prepare") .Does(async buildContext => { + await buildContext.BuildServer.BeforeUpdateInfoAsync(); + UpdateSolutionAssemblyInfo(buildContext); foreach (var processor in buildContext.Processors) { await processor.UpdateInfoAsync(); } + + await buildContext.BuildServer.AfterUpdateInfoAsync(); }); //------------------------------------------------------------- @@ -268,11 +355,14 @@ Task("Build") .IsDependentOn("CleanupCode") .Does(async buildContext => { + await buildContext.BuildServer.BeforeBuildAsync(); + await buildContext.SourceControl.MarkBuildAsPendingAsync("Build"); var sonarUrl = buildContext.General.SonarQube.Url; var enableSonar = !buildContext.General.SonarQube.IsDisabled && + buildContext.General.IsCiBuild && // Only build on CI (all projects need to be included) !string.IsNullOrWhiteSpace(sonarUrl); if (enableSonar) { @@ -343,6 +433,12 @@ Task("Build") foreach (var processor in buildContext.Processors) { + if (processor is TestProcessor) + { + // Build test projects *after* SonarQube (not part of SQ analysis) + continue; + } + await processor.BuildAsync(); } } @@ -388,35 +484,32 @@ Task("Build") var failedDescription = $"SonarQube failed, please visit '{projectSpecificSonarUrl}' for more details"; await buildContext.SourceControl.MarkBuildAsFailedAsync("SonarQube", failedDescription); + throw; } } } - var buildTestProjects = true; - - if (buildContext.General.IsLocalBuild && buildContext.General.MaximizePerformance) + var testProcessor = buildContext.Processors.FirstOrDefault(x => x is TestProcessor) as TestProcessor; + if (testProcessor is not null) { - Information("Local build with maximized performance detected, skipping test project(s) build"); - - buildTestProjects = false; - } - - // Build test projects *after* SonarQube (not part of SQ analysis). Unfortunately, because of this, we cannot yet mark - // the build as succeeded once we end the SQ session. Therefore, if SQ fails, both the SQ *and* build checks - // will be marked as failed if SQ fails. - if (buildTestProjects) - { - BuildTestProjects(buildContext); + // Build test projects *after* SonarQube (not part of SQ analysis). Unfortunately, because of this, we cannot yet mark + // the build as succeeded once we end the SQ session. Therefore, if SQ fails, both the SQ *and* build checks + // will be marked as failed if SQ fails. + await testProcessor.BuildAsync(); } await buildContext.SourceControl.MarkBuildAsSucceededAsync("Build"); Information("Completed build for version '{0}'", buildContext.General.Version.NuGet); + + await buildContext.BuildServer.AfterBuildAsync(); }) -.OnError((ex, buildContext) => +.OnError(async (ex, buildContext) => { - buildContext.SourceControl.MarkBuildAsFailedAsync("Build").Wait(); + await buildContext.SourceControl.MarkBuildAsFailedAsync("Build"); + + await buildContext.BuildServer.OnBuildFailedAsync(); throw ex; }); @@ -424,25 +517,104 @@ Task("Build") //------------------------------------------------------------- Task("Test") + .IsDependentOn("Prepare") // Note: no dependency on 'build' since we might have already built the solution .Does(async buildContext => -{ +{ + await buildContext.BuildServer.BeforeTestAsync(); + await buildContext.SourceControl.MarkBuildAsPendingAsync("Test"); - foreach (var testProject in buildContext.Tests.Items) + if (buildContext.Tests.Items.Count > 0) { - buildContext.CakeContext.LogSeparator("Running tests for '{0}'", testProject); + // If docker is involved, login to all registries for the unit / integration tests + var dockerRegistries = new HashSet(); + var dockerProcessor = (DockerImagesProcessor)buildContext.Processors.Single(x => x is DockerImagesProcessor); + + try + { + foreach (var dockerImage in buildContext.DockerImages.Items) + { + var dockerRegistryUrl = dockerProcessor.GetDockerRegistryUrl(dockerImage); + if (dockerRegistries.Contains(dockerRegistryUrl)) + { + continue; + } - RunUnitTests(buildContext, testProject); + // Note: we are logging in each time because the registry might be different per container + Information($"Logging in to docker @ '{dockerRegistryUrl}'"); + + dockerRegistries.Add(dockerRegistryUrl); + + var dockerRegistryUserName = dockerProcessor.GetDockerRegistryUserName(dockerImage); + var dockerRegistryPassword = dockerProcessor.GetDockerRegistryPassword(dockerImage); + + var dockerLoginSettings = new DockerRegistryLoginSettings + { + Username = dockerRegistryUserName, + Password = dockerRegistryPassword + }; + + DockerLogin(dockerLoginSettings, dockerRegistryUrl); + } + + // Always run all unit test projects before throwing + var failed = false; + + foreach (var testProject in buildContext.Tests.Items) + { + buildContext.CakeContext.LogSeparator("Running tests for '{0}'", testProject); + + try + { + RunUnitTests(buildContext, testProject); + } + catch (Exception ex) + { + failed = true; + + Warning($"Running tests for '{testProject}' caused an exception: {ex.Message}"); + } + } + + if (failed) + { + throw new Exception("At least 1 test project failed execution"); + } + } + finally + { + foreach (var dockerRegistry in dockerRegistries) + { + try + { + Information($"Logging out of docker @ '{dockerRegistry}'"); + + var dockerLogoutSettings = new DockerRegistryLogoutSettings + { + }; + + DockerLogout(dockerLogoutSettings, dockerRegistry); + } + catch (Exception ex) + { + Warning($"Failed to logout from docker: {ex.Message}"); + } + } + } } await buildContext.SourceControl.MarkBuildAsSucceededAsync("Test"); Information("Completed tests for version '{0}'", buildContext.General.Version.NuGet); + + await buildContext.BuildServer.AfterTestAsync(); }) -.OnError((ex, buildContext) => +.OnError(async (ex, buildContext) => { - buildContext.SourceControl.MarkBuildAsFailedAsync("Test").Wait(); + await buildContext.SourceControl.MarkBuildAsFailedAsync("Test"); + + await buildContext.BuildServer.OnTestFailedAsync(); throw ex; }); @@ -450,6 +622,8 @@ Task("Test") //------------------------------------------------------------- Task("Package") + // Make sure to update info so our SolutionAssemblyInfo.cs is up to date + .IsDependentOn("UpdateInfo") // Note: no dependency on 'build' since we might have already built the solution // Make sure we have the temporary "project.assets.json" in case we need to package with Visual Studio .IsDependentOn("RestorePackages") @@ -458,12 +632,16 @@ Task("Package") .IsDependentOn("CodeSign") .Does(async buildContext => { + await buildContext.BuildServer.BeforePackageAsync(); + foreach (var processor in buildContext.Processors) { await processor.PackageAsync(); } Information("Completed packaging for version '{0}'", buildContext.General.Version.NuGet); + + await buildContext.BuildServer.AfterPackageAsync(); }); //------------------------------------------------------------- @@ -472,6 +650,8 @@ Task("PackageLocal") .IsDependentOn("Package") .Does(buildContext => { + // Note: no build server integration calls since this is *local* + // For now only package components, we might need to move this to components-tasks.cake in the future if (buildContext.Components.Items.Count == 0 && buildContext.Tools.Items.Count == 0) @@ -514,10 +694,14 @@ Task("Deploy") .IsDependentOn("RestorePackages") .Does(async buildContext => { + await buildContext.BuildServer.BeforeDeployAsync(); + foreach (var processor in buildContext.Processors) { await processor.DeployAsync(); } + + await buildContext.BuildServer.AfterDeployAsync(); }); //------------------------------------------------------------- @@ -526,6 +710,8 @@ Task("Finalize") // Note: no dependency on 'deploy' since we might have already deployed the solution .Does(async buildContext => { + await buildContext.BuildServer.BeforeFinalizeAsync(); + Information("Finalizing release '{0}'", buildContext.General.Version.FullSemVer); foreach (var processor in buildContext.Processors) @@ -535,10 +721,12 @@ Task("Finalize") if (buildContext.General.IsOfficialBuild) { - buildContext.BuildServer.PinBuild("Official build"); + await buildContext.BuildServer.PinBuildAsync("Official build"); } await buildContext.IssueTracker.CreateAndReleaseVersionAsync(); + + await buildContext.BuildServer.AfterFinalizeAsync(); }); //------------------------------------------------------------- diff --git a/deployment/cake/templates-tasks.cake b/deployment/cake/templates-tasks.cake index baa39edf..6218ab1f 100644 --- a/deployment/cake/templates-tasks.cake +++ b/deployment/cake/templates-tasks.cake @@ -1,7 +1,5 @@ #l "templates-variables.cake" -#addin "nuget:?package=Cake.FileHelpers&version=3.0.0" - using System.Linq; using System.Text.RegularExpressions; using System.Xml.Linq; diff --git a/deployment/cake/tests-nunit.cake b/deployment/cake/tests-nunit.cake index 06fb12de..007db079 100644 --- a/deployment/cake/tests-nunit.cake +++ b/deployment/cake/tests-nunit.cake @@ -1,4 +1,4 @@ -#tool "nuget:?package=NUnit.ConsoleRunner&version=3.12.0" +#tool "nuget:?package=NUnit.ConsoleRunner&version=3.16.2" //------------------------------------------------------------- @@ -6,10 +6,9 @@ private static void RunTestsUsingNUnit(BuildContext buildContext, string project { var testFile = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), testTargetFramework, $"{projectName}.dll"); - var resultsFile = string.Format("{0}testresults.xml", testResultsDirectory); + var resultsFile = System.IO.Path.Combine(testResultsDirectory, "testresults.xml"); - // Note: although the docs say you can use without array initialization, you can't - buildContext.CakeContext.NUnit3(new string[] { testFile }, new NUnit3Settings + var nunitSettings = new NUnit3Settings { Results = new NUnit3Result[] { @@ -26,7 +25,10 @@ private static void RunTestsUsingNUnit(BuildContext buildContext, string project Timeout = 60 * 1000, // 60 seconds Workers = 1 //Work = testResultsDirectory - }); + }; + + // Note: although the docs say you can use without array initialization, you can't + buildContext.CakeContext.NUnit3(new string[] { testFile }, nunitSettings); buildContext.CakeContext.Information("Verifying whether results file '{0}' exists", resultsFile); diff --git a/deployment/cake/tests-variables.cake b/deployment/cake/tests-variables.cake index a6e3ee67..d56b36dc 100644 --- a/deployment/cake/tests-variables.cake +++ b/deployment/cake/tests-variables.cake @@ -47,7 +47,7 @@ private TestsContext InitializeTestsContext(BuildContext buildContext, IBuildCon Framework = buildContext.BuildServer.GetVariable("TestFramework", "nunit", showValue: true), TargetFramework = buildContext.BuildServer.GetVariable("TestTargetFramework", "", showValue: true), - ProcessBit = buildContext.BuildServer.GetVariable("TestProcessBit", "X86", showValue: true) + ProcessBit = buildContext.BuildServer.GetVariable("TestProcessBit", "X64", showValue: true) }; return data; diff --git a/deployment/cake/tests.cake b/deployment/cake/tests.cake index ddbfd32a..36f216c9 100644 --- a/deployment/cake/tests.cake +++ b/deployment/cake/tests.cake @@ -2,73 +2,128 @@ #l "tests-variables.cake" #l "tests-nunit.cake" -private static bool IgnoreTestProject(BuildContext buildContext, string projectName) +public class TestProcessor : ProcessorBase { - // In case of a local build and we have included / excluded anything, skip tests - if (buildContext.General.IsLocalBuild && - (buildContext.General.Includes.Count > 0 || buildContext.General.Excludes.Count > 0)) + public TestProcessor(BuildContext buildContext) + : base(buildContext) { - buildContext.CakeContext.Information($"Skipping test project '{projectName}' because this is a local build with specific includes / excludes"); - return true; + } - // Special unit test part assuming a few naming conventions: - // 1. [ProjectName].Tests - // 2. [SolutionName].Tests.[ProjectName] - // - // In both cases, we can simply remove ".Tests" and check if that project is being ignored - var expectedProjectName = projectName.Replace(".Tests", string.Empty); - if (!ShouldProcessProject(buildContext, expectedProjectName)) + public override bool HasItems() { - buildContext.CakeContext.Information($"Skipping test project '{projectName}' because project '{expectedProjectName}' should not be processed either"); - return true; + return BuildContext.Tests.Items.Count > 0; } - return false; -} + public override async Task PrepareAsync() + { + // Check whether projects should be processed, `.ToList()` + // is required to prevent issues with foreach + foreach (var testProject in BuildContext.Tests.Items.ToList()) + { + if (IgnoreTestProject(testProject)) + { + BuildContext.Tests.Items.Remove(testProject); + } + } + } -//------------------------------------------------------------- + public override async Task UpdateInfoAsync() + { + // Not required + } -private static void BuildTestProjects(BuildContext buildContext) -{ - foreach (var testProject in buildContext.Tests.Items) + public override async Task BuildAsync() { - if (IgnoreTestProject(buildContext, testProject)) + if (!HasItems()) { - continue; + return; } - buildContext.CakeContext.LogSeparator("Building test project '{0}'", testProject); - - var projectFileName = GetProjectFileName(buildContext, testProject); - - var msBuildSettings = new MSBuildSettings + foreach (var testProject in BuildContext.Tests.Items) { - Verbosity = Verbosity.Quiet, // Verbosity.Diagnostic - ToolVersion = MSBuildToolVersion.Default, - Configuration = buildContext.General.Solution.ConfigurationName, - MSBuildPlatform = MSBuildPlatform.x86, // Always require x86, see platform for actual target platform - PlatformTarget = PlatformTarget.MSIL - }; + BuildContext.CakeContext.LogSeparator("Building test project '{0}'", testProject); - ConfigureMsBuild(buildContext, msBuildSettings, testProject); + var projectFileName = GetProjectFileName(BuildContext, testProject); + + var msBuildSettings = new MSBuildSettings + { + Verbosity = Verbosity.Quiet, // Verbosity.Diagnostic + ToolVersion = MSBuildToolVersion.Default, + Configuration = BuildContext.General.Solution.ConfigurationName, + MSBuildPlatform = MSBuildPlatform.x86, // Always require x86, see platform for actual target platform + PlatformTarget = PlatformTarget.MSIL + }; - // Always disable SourceLink - msBuildSettings.WithProperty("EnableSourceLink", "false"); + ConfigureMsBuild(BuildContext, msBuildSettings, testProject, "build"); - // Force disable SonarQube - msBuildSettings.WithProperty("SonarQubeExclude", "true"); + // Always disable SourceLink + msBuildSettings.WithProperty("EnableSourceLink", "false"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = GetProjectOutputDirectory(buildContext, testProject); - buildContext.CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", buildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", buildContext.General.OutputRootDirectory); + // Force disable SonarQube + msBuildSettings.WithProperty("SonarQubeExclude", "true"); - RunMsBuild(buildContext, testProject, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, testProject, projectFileName, msBuildSettings, "build"); + } + } + + public override async Task PackageAsync() + { + // Not required + } + + public override async Task DeployAsync() + { + // Not required + } + + public override async Task FinalizeAsync() + { + // Not required + } + + //------------------------------------------------------------- + + private bool IgnoreTestProject(string projectName) + { + if (BuildContext.General.IsLocalBuild && BuildContext.General.MaximizePerformance) + { + BuildContext.CakeContext.Information($"Local build with maximized performance detected, ignoring test project for project '{projectName}'"); + return true; + } + + // In case of a local build and we have included / excluded anything, skip tests + if (BuildContext.General.IsLocalBuild && + (BuildContext.General.Includes.Count > 0 || BuildContext.General.Excludes.Count > 0)) + { + BuildContext.CakeContext.Information($"Skipping test project '{projectName}' because this is a local build with specific includes / excludes"); + return true; + } + + // Special unit test part assuming a few naming conventions: + // 1. [ProjectName].Tests + // 2. [SolutionName].Tests.[ProjectName] + // + // In both cases, we can simply remove ".Tests" and check if that project is being ignored + var expectedProjectName = projectName + .Replace(".Integration.Tests", string.Empty) + .Replace(".IntegrationTests", string.Empty) + .Replace(".Tests", string.Empty); + + // Special case: if this is a "solution wide" test project, it must always run + if (!BuildContext.RegisteredProjects.Any(x => string.Equals(x, expectedProjectName, StringComparison.OrdinalIgnoreCase))) + { + BuildContext.CakeContext.Information($"Including test project '{projectName}' because there are no linked projects, assuming this is a solution wide test project"); + return false; + } + + if (!ShouldProcessProject(BuildContext, expectedProjectName)) + { + BuildContext.CakeContext.Information($"Skipping test project '{projectName}' because project '{expectedProjectName}' should not be processed either"); + return true; + } + + return false; } } @@ -76,13 +131,7 @@ private static void BuildTestProjects(BuildContext buildContext) private static void RunUnitTests(BuildContext buildContext, string projectName) { - if (IgnoreTestProject(buildContext, projectName)) - { - return; - } - - var testResultsDirectory = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, - "testresults", projectName); + var testResultsDirectory = System.IO.Path.Combine(buildContext.General.OutputRootDirectory, "testresults", projectName); buildContext.CakeContext.CreateDirectory(testResultsDirectory); @@ -94,37 +143,53 @@ private static void RunUnitTests(BuildContext buildContext, string projectName) { if (IsDotNetCoreProject(buildContext, projectName)) { - buildContext.CakeContext.Information("Project '{0}' is a .NET core project, using 'dotnet test' to run the unit tests", projectName); + buildContext.CakeContext.Information($"Project '{projectName}' is a .NET core project, using 'dotnet test' to run the unit tests"); var projectFileName = GetProjectFileName(buildContext, projectName); - buildContext.CakeContext.DotNetCoreTest(projectFileName, new DotNetCoreTestSettings + var dotNetTestSettings = new DotNetTestSettings { Configuration = buildContext.General.Solution.ConfigurationName, + // Loggers = new [] + // { + // "nunit;LogFilePath=test-result.xml" + // }, NoBuild = true, NoLogo = true, NoRestore = true, OutputDirectory = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), testTargetFramework), ResultsDirectory = testResultsDirectory - }); + }; - // Information("Project '{0}' is a .NET core project, using 'dotnet vstest' to run the unit tests", projectName); + if (IsNUnitTestProject(buildContext, projectName)) + { + dotNetTestSettings.ArgumentCustomization = args => args + .Append($"-- NUnit.TestOutputXml={testResultsDirectory}"); + } + + if (IsXUnitTestProject(buildContext, projectName)) + { + var outputFileName = System.IO.Path.Combine(testResultsDirectory, $"{projectName}.xml"); - // var testFile = string.Format("{0}/{1}/{2}.dll", GetProjectOutputDirectory(buildContext, projectName), testTargetFramework, projectName); + dotNetTestSettings.ArgumentCustomization = args => args + .Append($"-l:trx;LogFileName={outputFileName}"); + } + + var processBit = buildContext.Tests.ProcessBit.ToLower(); + if (!string.IsNullOrWhiteSpace(processBit)) + { + dotNetTestSettings.Runtime = $"win-{processBit}"; + } - // DotNetCoreVSTest(testFile, new DotNetCoreVSTestSettings - // { - // //Platform = TestFramework - // ResultsDirectory = testResultsDirectory - // }); + buildContext.CakeContext.DotNetTest(projectFileName, dotNetTestSettings); ranTests = true; } else { - buildContext.CakeContext.Information("Project '{0}' is a .NET project, using '{1} runner' to run the unit tests", projectName, buildContext.Tests.Framework); + buildContext.CakeContext.Information($"Project '{projectName}' is a .NET project, using '{buildContext.Tests.Framework} runner' to run the unit tests"); - if (buildContext.Tests.Framework.ToLower().Equals("nunit")) + if (IsNUnitTestProject(buildContext, projectName)) { RunTestsUsingNUnit(buildContext, projectName, testTargetFramework, testResultsDirectory); @@ -134,14 +199,14 @@ private static void RunUnitTests(BuildContext buildContext, string projectName) } catch (Exception ex) { - buildContext.CakeContext.Warning("An exception occurred: {0}", ex.Message); + buildContext.CakeContext.Warning($"An exception occurred: {ex.Message}"); failed = true; } if (ranTests) { - buildContext.CakeContext.Information("Results are available in '{0}'", testResultsDirectory); + buildContext.CakeContext.Information($"Results are available in '{testResultsDirectory}'"); } else if (failed) { @@ -155,6 +220,59 @@ private static void RunUnitTests(BuildContext buildContext, string projectName) //------------------------------------------------------------- +private static bool IsTestProject(BuildContext buildContext, string projectName) +{ + if (IsNUnitTestProject(buildContext, projectName)) + { + return true; + } + + if (IsXUnitTestProject(buildContext, projectName)) + { + return true; + } + + return false; +} + +//------------------------------------------------------------- + +private static bool IsNUnitTestProject(BuildContext buildContext, string projectName) +{ + var projectFileName = GetProjectFileName(buildContext, projectName); + var projectFileContents = System.IO.File.ReadAllText(projectFileName); + + if (projectFileContents.ToLower().Contains("nunit")) + { + return true; + } + + return false; + + // Not sure, return framework from config + //return buildContext.Tests.Framework.ToLower().Equals("nunit"); +} + +//------------------------------------------------------------- + +private static bool IsXUnitTestProject(BuildContext buildContext, string projectName) +{ + var projectFileName = GetProjectFileName(buildContext, projectName); + var projectFileContents = System.IO.File.ReadAllText(projectFileName); + + if (projectFileContents.ToLower().Contains("xunit")) + { + return true; + } + + return false; + + // Not sure, return framework from config + //return buildContext.Tests.Framework.ToLower().Equals("xunit"); +} + +//------------------------------------------------------------- + private static string GetTestTargetFramework(BuildContext buildContext, string projectName) { // Step 1: if defined, use defined value diff --git a/deployment/cake/tools-tasks.cake b/deployment/cake/tools-tasks.cake index 351c3ca8..a481eaad 100644 --- a/deployment/cake/tools-tasks.cake +++ b/deployment/cake/tools-tasks.cake @@ -209,16 +209,7 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, tool); - - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - var outputDirectory = GetProjectOutputDirectory(BuildContext, tool); - CakeContext.Information("Output directory: '{0}'", outputDirectory); - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); + ConfigureMsBuild(BuildContext, msBuildSettings, tool, "build"); // SourceLink specific stuff var repositoryUrl = BuildContext.General.Repository.Url; @@ -239,10 +230,10 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: msBuildSettings.WithProperty("RepositoryUrl", repositoryUrl); msBuildSettings.WithProperty("RevisionId", repositoryCommitId); - InjectSourceLinkInProjectFile(BuildContext, projectFileName); + InjectSourceLinkInProjectFile(BuildContext, tool, projectFileName); } - RunMsBuild(BuildContext, tool, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, tool, projectFileName, msBuildSettings, "build"); } } @@ -258,9 +249,9 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: foreach (var tool in BuildContext.Tools.Items) { - if (!ShouldDeployProject(BuildContext, tool)) + if (!ShouldPackageProject(BuildContext, tool)) { - CakeContext.Information("Tool '{0}' should not be deployed", tool); + CakeContext.Information("Tool '{0}' should not be packaged", tool); continue; } @@ -306,8 +297,8 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: BuildContext.CakeContext.Information($" - {dllSignFilesSearchPattern}"); projectFilesToSign.AddRange(BuildContext.CakeContext.GetFiles(dllSignFilesSearchPattern)); - var signToolCommand = string.Format("sign /a /t {0} /n {1}", BuildContext.General.CodeSign.TimeStampUri, - BuildContext.General.CodeSign.CertificateSubjectName); + var signToolCommand = string.Format("sign /a /t {0} /n {1} /fd {2}", BuildContext.General.CodeSign.TimeStampUri, + BuildContext.General.CodeSign.CertificateSubjectName, BuildContext.General.CodeSign.HashAlgorithm); SignFiles(BuildContext, signToolCommand, projectFilesToSign); } @@ -325,7 +316,8 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: // Step 3: Go packaging! CakeContext.Information("Using 'msbuild' to package '{0}'", tool); - var msBuildSettings = new MSBuildSettings { + var msBuildSettings = new MSBuildSettings + { Verbosity = Verbosity.Quiet, //Verbosity = Verbosity.Diagnostic, ToolVersion = MSBuildToolVersion.Default, @@ -336,12 +328,6 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: ConfigureMsBuild(BuildContext, msBuildSettings, tool, "pack"); - // Note: we need to set OverridableOutputPath because we need to be able to respect - // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which - // are properties passed in using the command line) - msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - msBuildSettings.WithProperty("PackageOutputPath", BuildContext.General.OutputRootDirectory); msBuildSettings.WithProperty("ConfigurationName", configurationName); msBuildSettings.WithProperty("PackageVersion", version); @@ -377,12 +363,12 @@ SHA512 CHECKSUMS GENERATED BY BUILD TOOL: msBuildSettings.WithProperty("NoDefaultExcludes", "true"); // Ensures that files are written to "tools", not "tools\\netcoreapp3.1" - msBuildSettings.WithProperty("IsTool", "true"); + msBuildSettings.WithProperty("IsTool", "false"); msBuildSettings.WithProperty("NoBuild", "true"); msBuildSettings.Targets.Add("Pack"); - RunMsBuild(BuildContext, tool, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, tool, projectFileName, msBuildSettings, "pack"); BuildContext.CakeContext.LogSeparator(); } diff --git a/deployment/cake/vsextensions-tasks.cake b/deployment/cake/vsextensions-tasks.cake index 980d01f3..9903d1dd 100644 --- a/deployment/cake/vsextensions-tasks.cake +++ b/deployment/cake/vsextensions-tasks.cake @@ -85,7 +85,7 @@ public class VsExtensionsProcessor : ProcessorBase PlatformTarget = PlatformTarget.MSIL }; - ConfigureMsBuild(BuildContext, msBuildSettings, vsExtension); + ConfigureMsBuild(BuildContext, msBuildSettings, vsExtension, "build"); // Note: we need to set OverridableOutputPath because we need to be able to respect // AppendTargetFrameworkToOutputPath which isn't possible for global properties (which @@ -95,12 +95,9 @@ public class VsExtensionsProcessor : ProcessorBase // Since vs extensions (for now) use the old csproj style, make sure // to override the output path as well - //msBuildSettings.WithProperty("OverridableOutputRootPath", BuildContext.General.OutputRootDirectory); - // msBuildSettings.WithProperty("OverridableOutputPath", outputDirectory); - // msBuildSettings.WithProperty("PackageOutputPath", OutputRootDirectory); msBuildSettings.WithProperty("OutputPath", outputDirectory); - RunMsBuild(BuildContext, vsExtension, projectFileName, msBuildSettings); + RunMsBuild(BuildContext, vsExtension, projectFileName, msBuildSettings, "build"); } } diff --git a/src/.vsconfig b/src/.vsconfig index e8e94318..98c42001 100644 --- a/src/.vsconfig +++ b/src/.vsconfig @@ -4,7 +4,6 @@ "Microsoft.VisualStudio.Component.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor", "Microsoft.VisualStudio.Component.NuGet", - "Microsoft.Net.Component.4.6.1.TargetingPack", "Microsoft.VisualStudio.Component.Roslyn.Compiler", "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", "Microsoft.VisualStudio.Component.FSharp", @@ -14,8 +13,6 @@ "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions", "Microsoft.VisualStudio.Component.DockerTools", "Microsoft.NetCore.ComponentGroup.Web.2.1", - "Microsoft.Net.Component.4.7.2.SDK", - "Microsoft.Net.Component.4.7.2.TargetingPack", "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites", "Microsoft.VisualStudio.Component.TypeScript.3.4", "Microsoft.VisualStudio.Component.JavaScript.TypeScript", @@ -31,23 +28,12 @@ "Microsoft.VisualStudio.Component.MSODBC.SQL", "Microsoft.VisualStudio.Component.MSSQL.CMDLnUtils", "Microsoft.VisualStudio.Component.ManagedDesktop.Core", - "Microsoft.Net.Component.4.5.2.TargetingPack", - "Microsoft.Net.Component.4.5.TargetingPack", "Microsoft.VisualStudio.Component.SQL.SSDT", "Microsoft.VisualStudio.Component.SQL.DataSources", "Component.Microsoft.Web.LibraryManager", "Microsoft.VisualStudio.ComponentGroup.Web", "Microsoft.VisualStudio.Component.Web", - "Microsoft.Net.Component.4.TargetingPack", - "Microsoft.Net.Component.4.5.1.TargetingPack", - "Microsoft.Net.Component.4.6.TargetingPack", "Microsoft.Net.ComponentGroup.TargetingPacks.Common", - "Component.Microsoft.VisualStudio.Web.AzureFunctions", - "Microsoft.VisualStudio.ComponentGroup.AzureFunctions", - "Microsoft.VisualStudio.Component.Azure.Compute.Emulator", - "Microsoft.VisualStudio.Component.Azure.Storage.Emulator", - "Microsoft.VisualStudio.Component.Azure.ClientLibs", - "Microsoft.VisualStudio.Component.Azure.AuthoringTools", "Microsoft.VisualStudio.Component.CloudExplorer", "Microsoft.VisualStudio.Component.Debugger.TimeTravel", "Microsoft.VisualStudio.Component.Debugger.Snapshot", @@ -60,65 +46,21 @@ "Microsoft.VisualStudio.Component.AppInsights.Tools", "Microsoft.VisualStudio.Component.WebDeploy", "Microsoft.VisualStudio.Component.Debugger.JustInTime", - "Microsoft.Net.Component.4.6.1.SDK", - "Microsoft.Net.Component.4.6.2.SDK", - "Microsoft.Net.Component.4.6.2.TargetingPack", - "Microsoft.Net.Component.4.7.SDK", - "Microsoft.Net.Component.4.7.TargetingPack", - "Microsoft.Net.Component.4.7.1.SDK", - "Microsoft.Net.Component.4.7.1.TargetingPack", "Microsoft.VisualStudio.Component.GraphDocument", "Microsoft.VisualStudio.Component.CodeMap", "Microsoft.VisualStudio.Workload.NetWeb", - "Microsoft.VisualStudio.ComponentGroup.Azure.Prerequisites", - "Microsoft.VisualStudio.Component.Azure.Waverton.BuildTools", - "Microsoft.VisualStudio.Component.Azure.Waverton", - "Microsoft.Component.Azure.DataLake.Tools", - "Microsoft.VisualStudio.Component.Azure.Kubernetes.Tools", - "Microsoft.VisualStudio.Component.Azure.ResourceManager.Tools", - "Microsoft.VisualStudio.ComponentGroup.Azure.ResourceManager.Tools", - "Microsoft.VisualStudio.ComponentGroup.Azure.CloudServices", - "Microsoft.VisualStudio.Component.Azure.ServiceFabric.Tools", - "Microsoft.VisualStudio.Workload.Azure", - "Microsoft.VisualStudio.Component.VC.CoreIde", - "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", - "Microsoft.VisualStudio.Component.Windows10SDK.17763", "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", - "Microsoft.ComponentGroup.Blend", "Microsoft.VisualStudio.Component.PortableLibrary", "Microsoft.VisualStudio.Workload.ManagedDesktop", - "Microsoft.VisualStudio.Component.VC.Redist.14.Latest", "Microsoft.VisualStudio.Component.ClassDesigner", - "Microsoft.VisualStudio.Component.VC.ATL", - "Microsoft.VisualStudio.Component.VC.ATLMFC", - "Microsoft.VisualStudio.Component.Windows10SDK.17134", - "Microsoft.VisualStudio.Component.Windows10SDK.16299", "Microsoft.Component.NetFX.Native", "Microsoft.VisualStudio.ComponentGroup.UWP.NetCoreAndStandard", "Microsoft.VisualStudio.Component.Graphics", - "Microsoft.VisualStudio.ComponentGroup.UWP.Xamarin", - "Microsoft.VisualStudio.ComponentGroup.UWP.Support", - "Microsoft.VisualStudio.Component.VC.Tools.ARM64", - "Microsoft.VisualStudio.Component.VC.Tools.ARM", "Microsoft.VisualStudio.Component.Windows10SDK.18362", "Microsoft.VisualStudio.Workload.Universal", - "Component.OpenJDK", - "Microsoft.VisualStudio.Component.MonoDebugger", "Microsoft.VisualStudio.Component.Merq", - "Component.Xamarin.RemotedSimulator", "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.TemplateEngine", - "Component.Xamarin", - "Component.Android.SDK27", "Microsoft.VisualStudio.Workload.NetCrossPlat", - "Microsoft.Component.CodeAnalysis.SDK", - "Microsoft.VisualStudio.Component.VC.ATL.ARM", - "Microsoft.VisualStudio.Component.VC.ATL.ARM64", - "Microsoft.VisualStudio.Component.VC.MFC.ARM", - "Microsoft.VisualStudio.Component.VC.MFC.ARM64", - "Microsoft.VisualStudio.Component.VC.v141.ATL.ARM64", - "Microsoft.VisualStudio.Component.VC.v141.ATL", - "Microsoft.VisualStudio.Component.VC.v141.MFC.ARM", - "Microsoft.VisualStudio.Component.VC.v141.MFC.ARM64", - "Microsoft.VisualStudio.Component.VC.v141.MFC" + "Microsoft.Component.CodeAnalysis.SDK" ] } \ No newline at end of file diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/ImplementsInterfaceAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/ImplementsInterfaceAttribute.cs index 23ac07b9..f6ffc92f 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/ImplementsInterfaceAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/ImplementsInterfaceAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/InheritsFromAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/InheritsFromAttribute.cs index b1f0d018..c0f29c37 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/InheritsFromAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/InheritsFromAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; @@ -15,7 +9,6 @@ namespace Catel.Fody [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] public class InheritsFromAttribute : Attribute { - #region Constructors /// /// Initializes a new instance of the class. /// @@ -23,6 +16,5 @@ public class InheritsFromAttribute : Attribute public InheritsFromAttribute(Type type) { } - #endregion } } diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/MatchAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/MatchAttribute.cs index 8ff8b204..e7a17e1c 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/MatchAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/MatchAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Text.RegularExpressions; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/MaximumAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/MaximumAttribute.cs index 388a401c..97ceaf0b 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/MaximumAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/MaximumAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/MinimalAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/MinimalAttribute.cs index 98d441fa..03537217 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/MinimalAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/MinimalAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotMatchAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotMatchAttribute.cs index e63d19a9..282aaf04 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotMatchAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotMatchAttribute.cs @@ -1,9 +1,3 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullAttribute.cs index 229d2204..fcf9a869 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyArrayAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyArrayAttribute.cs index 8032dd67..fd0d5d2c 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyArrayAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyArrayAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyAttribute.cs index cd662b99..9d2f3f8d 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrEmptyAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrWhitespaceAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrWhitespaceAttribute.cs index 80d298e3..c6900d80 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrWhitespaceAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotNullOrWhitespaceAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/NotOutOfRangeAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/NotOutOfRangeAttribute.cs index 583cca3c..c1be47bb 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/NotOutOfRangeAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/NotOutOfRangeAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/ArgumentAttributes/OfTypeAttribute.cs b/src/Catel.Fody.Attributes/ArgumentAttributes/OfTypeAttribute.cs index 3c4b6bb2..1a6dbe01 100644 --- a/src/Catel.Fody.Attributes/ArgumentAttributes/OfTypeAttribute.cs +++ b/src/Catel.Fody.Attributes/ArgumentAttributes/OfTypeAttribute.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/Catel.Fody.Attributes.csproj b/src/Catel.Fody.Attributes/Catel.Fody.Attributes.csproj index f6239e8b..6d364bf8 100644 --- a/src/Catel.Fody.Attributes/Catel.Fody.Attributes.csproj +++ b/src/Catel.Fody.Attributes/Catel.Fody.Attributes.csproj @@ -1,6 +1,6 @@  - net452;netstandard1.0 + net452;net6.0;netstandard1.0;netstandard2.0;netstandard2.1 Catel.Fody.Attributes Catel.Fody en-US @@ -19,7 +19,7 @@ - + diff --git a/src/Catel.Fody.Attributes/NoWeavingAttribute.cs b/src/Catel.Fody.Attributes/NoWeavingAttribute.cs index 16c40c21..ec840dd6 100644 --- a/src/Catel.Fody.Attributes/NoWeavingAttribute.cs +++ b/src/Catel.Fody.Attributes/NoWeavingAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.Attributes/PropertyAttributes/ExposeAttribute.cs b/src/Catel.Fody.Attributes/PropertyAttributes/ExposeAttribute.cs index 0fab2b59..7fb90d0d 100644 --- a/src/Catel.Fody.Attributes/PropertyAttributes/ExposeAttribute.cs +++ b/src/Catel.Fody.Attributes/PropertyAttributes/ExposeAttribute.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; diff --git a/src/Catel.Fody.TestAssembly.Catel5/Catel.Fody.TestAssembly.Catel5.csproj b/src/Catel.Fody.TestAssembly.Catel5/Catel.Fody.TestAssembly.Catel5.csproj index f57e13f3..2cc26b90 100644 --- a/src/Catel.Fody.TestAssembly.Catel5/Catel.Fody.TestAssembly.Catel5.csproj +++ b/src/Catel.Fody.TestAssembly.Catel5/Catel.Fody.TestAssembly.Catel5.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.TestAssembly.Catel5 Catel.Fody.TestAssembly en-US @@ -19,10 +19,6 @@ - - - - diff --git a/src/Catel.Fody.TestAssembly.Catel6/Catel.Fody.TestAssembly.Catel6.csproj b/src/Catel.Fody.TestAssembly.Catel6/Catel.Fody.TestAssembly.Catel6.csproj index b40ca912..dcb056e9 100644 --- a/src/Catel.Fody.TestAssembly.Catel6/Catel.Fody.TestAssembly.Catel6.csproj +++ b/src/Catel.Fody.TestAssembly.Catel6/Catel.Fody.TestAssembly.Catel6.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.TestAssembly.Catel6 Catel.Fody.TestAssembly en-US @@ -15,14 +15,9 @@ - - - - - diff --git a/src/Catel.Fody.TestAssembly.NetStandard.Catel5/Catel.Fody.TestAssembly.NetStandard.Catel5.csproj b/src/Catel.Fody.TestAssembly.NetStandard.Catel5/Catel.Fody.TestAssembly.NetStandard.Catel5.csproj index 7abedba1..51ac7771 100644 --- a/src/Catel.Fody.TestAssembly.NetStandard.Catel5/Catel.Fody.TestAssembly.NetStandard.Catel5.csproj +++ b/src/Catel.Fody.TestAssembly.NetStandard.Catel5/Catel.Fody.TestAssembly.NetStandard.Catel5.csproj @@ -14,11 +14,7 @@ - - - - - + diff --git a/src/Catel.Fody.TestAssembly.NetStandard.Catel6/Catel.Fody.TestAssembly.NetStandard.Catel6.csproj b/src/Catel.Fody.TestAssembly.NetStandard.Catel6/Catel.Fody.TestAssembly.NetStandard.Catel6.csproj deleted file mode 100644 index ba2a406d..00000000 --- a/src/Catel.Fody.TestAssembly.NetStandard.Catel6/Catel.Fody.TestAssembly.NetStandard.Catel6.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - netstandard2.0 - Catel.Fody.TestAssembly.NetStandard.Catel6 - Catel.Fody.TestAssembly - en-US - Catel.Fody.TestAssembly.NetStandard - 1.0.0-alpha0001 - Catel.Fody.TestAssembly.NetStandard library. - - true - true - $(DefineConstants);CATEL_6 - - - - - - - - - - - - - - - - - diff --git a/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksAsExpressionsClass.cs b/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksAsExpressionsClass.cs index 806cbe53..4f973207 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksAsExpressionsClass.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksAsExpressionsClass.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System; using System.Collections; @@ -110,7 +103,7 @@ public async Task CheckForNullAsync(object myObject) } #pragma warning disable 1998 - public async Task CheckForNullAsync_Expected(object myObject) + public async Task CheckForNullAsync_ExpectedAsync(object myObject) #pragma warning restore 1998 { Argument.IsNotNull("myObject", myObject); @@ -119,7 +112,7 @@ public async Task CheckForNullAsync_Expected(object myObject) } #pragma warning disable 1998 - public async Task CheckForNullAsync_MultipleParameters(object myObject1, object myObject2, object myObject3) + public async Task CheckForNullAsync_MultipleParametersAsync(object myObject1, object myObject2, object myObject3) #pragma warning restore 1998 { Argument.IsNotNull(() => myObject1); @@ -130,7 +123,7 @@ public async Task CheckForNullAsync_MultipleParameters(object myObject1, object } #pragma warning disable 1998 - public async Task CheckForNullAsync_MultipleParameters_Expected(object myObject1, object myObject2, object myObject3) + public async Task CheckForNullAsync_MultipleParameters_ExpectedAsync(object myObject1, object myObject2, object myObject3) #pragma warning restore 1998 { Argument.IsNotNull("myObject1", myObject1); @@ -141,7 +134,7 @@ public async Task CheckForNullAsync_MultipleParameters_Expected(object myObject1 } #pragma warning disable 1998 - public async Task CheckForNullAsync_MultipleParameters_Usages(object myObject1, object myObject2, object myObject3) + public async Task CheckForNullAsync_MultipleParameters_UsagesAsync(object myObject1, object myObject2, object myObject3) #pragma warning restore 1998 { Argument.IsNotNull(() => myObject1); @@ -152,7 +145,7 @@ public async Task CheckForNullAsync_MultipleParameters_Usages(object myObject1, } #pragma warning disable 1998 - public async Task CheckForNullAsync_MultipleParameters_Usages_Expected(object myObject1, object myObject2, object myObject3) + public async Task CheckForNullAsync_MultipleParameters_Usages_ExpectedAsync(object myObject1, object myObject2, object myObject3) #pragma warning restore 1998 { Argument.IsNotNull("myObject1", myObject1); diff --git a/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksClass.cs b/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksClass.cs index 724d8800..1020292b 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksClass.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ArgumentChecksClass.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System; diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL504.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL504.cs index f7604b14..83e029ec 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL504.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL504.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL569.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL569.cs index 1b1305a7..1243ec3d 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL569.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL569.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2015 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System; using MVVM; @@ -19,7 +12,7 @@ public class CTL569_ViewModel : ViewModelBase public bool SearchIsEnabled { - get { return !string.IsNullOrWhiteSpace(SearchTerms) && SelectedFeed != null; } + get { return !string.IsNullOrWhiteSpace(SearchTerms) && SelectedFeed is not null; } } #if CATEL_5 diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL908.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL908.cs index 1a398939..774a69c7 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL908.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/CTL908.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2016 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Catel; diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0008.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0008.cs index c2d3b8d2..07288dac 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0008.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0008.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Data; using MVVM; @@ -114,7 +107,7 @@ public bool IsExpandedAllOnStartup #if CATEL_5 public static readonly PropertyData IsExpandedAllOnStartupProperty = RegisterProperty("IsExpandedAllOnStartup", typeof(bool), false); #elif CATEL_6 - public static readonly IPropertyData IsExpandedAllOnStartupProperty = RegisterProperty("IsExpandedAllOnStartup", typeof(bool), false); + public static readonly IPropertyData IsExpandedAllOnStartupProperty = RegisterProperty("IsExpandedAllOnStartup", false); #endif public IValidationContext ValidationContext @@ -126,7 +119,7 @@ public IValidationContext ValidationContext #if CATEL_5 public static readonly PropertyData ValidationContextProperty = RegisterProperty("ValidationContext", typeof(IValidationContext), null); #elif CATEL_6 - public static readonly IPropertyData ValidationContextProperty = RegisterProperty("ValidationContext", typeof(IValidationContext), null); + public static readonly IPropertyData ValidationContextProperty = RegisterProperty("ValidationContext"); #endif public bool ShowErrors @@ -138,7 +131,7 @@ public bool ShowErrors #if CATEL_5 public static readonly PropertyData ShowErrorsProperty = RegisterProperty("ShowErrors", typeof(bool), true); #elif CATEL_6 - public static readonly IPropertyData ShowErrorsProperty = RegisterProperty("ShowErrors", typeof(bool), true); + public static readonly IPropertyData ShowErrorsProperty = RegisterProperty("ShowErrors", true); #endif public bool ShowWarnings @@ -150,7 +143,7 @@ public bool ShowWarnings #if CATEL_5 public static readonly PropertyData ShowWarningsProperty = RegisterProperty("ShowWarnings", typeof(bool), true); #elif CATEL_6 - public static readonly IPropertyData ShowWarningsProperty = RegisterProperty("ShowWarnings", typeof(bool), true); + public static readonly IPropertyData ShowWarningsProperty = RegisterProperty("ShowWarnings", true); #endif public bool IsExpanded @@ -162,7 +155,7 @@ public bool IsExpanded #if CATEL_5 public static readonly PropertyData IsExpandedProperty = RegisterProperty("IsExpanded", typeof(bool), false); #elif CATEL_6 - public static readonly IPropertyData IsExpandedProperty = RegisterProperty("IsExpanded", typeof(bool), false); + public static readonly IPropertyData IsExpandedProperty = RegisterProperty("IsExpanded", false); #endif public bool IsCollapsed => !IsExpanded; diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0012.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0012.cs index 1e831120..46af5cf8 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0012.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0012.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using MVVM; diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyDerivedService.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyDerivedService.cs index f0b87ab6..968715b2 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyDerivedService.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyDerivedService.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2018 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly.Bugs.GH0021 +namespace Catel.Fody.TestAssembly.Bugs.GH0021 { public class MyDerivedService : MyService { diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyService.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyService.cs index a543e77c..436db952 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyService.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0021/MyService.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2018 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly.Bugs.GH0021 +namespace Catel.Fody.TestAssembly.Bugs.GH0021 { public abstract class MyService { diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0291.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0291.cs index 2a9eee1b..734588a3 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0291.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0291.cs @@ -30,7 +30,7 @@ public Person() public virtual Address Address { get; set; } public Address Address2 { get; set; } - public bool HasAddress => Address != null; - public bool HasAddress2 => Address2 != null; + public bool HasAddress => Address is not null; + public bool HasAddress2 => Address2 is not null; } } diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0295.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0295.cs index 82640ee1..643c1b98 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0295.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0295.cs @@ -1,4 +1,6 @@ -namespace Catel.Fody.TestAssembly.Bugs.GH0295 +#if CATEL_5 + +namespace Catel.Fody.TestAssembly.Bugs.GH0295 { using System; using System.Collections.Generic; @@ -9,3 +11,5 @@ public class ModelReferencingNetStandard : NetStandardModel { } } + +#endif diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0361.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0361.cs new file mode 100644 index 00000000..6da2289a --- /dev/null +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0361.cs @@ -0,0 +1,23 @@ +namespace Catel.Fody.TestAssembly.Bugs.GH0361 +{ + using Catel.MVVM; + + public class MyDerivedViewModel : ViewModelBase + { + [Model] + public TestModel Model { get; set; } + + [ViewModelToModel] + public object Property { get; set; } + + public void SetValue(string s) + { + + } + } + + public class TestModel + { + public object Property { get; set; } + } +} diff --git a/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0473.cs b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0473.cs new file mode 100644 index 00000000..741be33e --- /dev/null +++ b/src/Catel.Fody.TestAssembly.Shared/Bugs/GH0473.cs @@ -0,0 +1,61 @@ +namespace Catel.Fody.TestAssembly.Bugs.GH0473 +{ + using System; + using Catel.Data; + using Catel.MVVM; + + public class GH0473ViewModel : ViewModelBase + { + public GH0473ViewModel(TestModel testModel) + { + ArgumentNullException.ThrowIfNull(testModel); + + Model = testModel; + } + + [Model(SupportIEditableObject = false, SupportValidation = false)] + [Expose(nameof(TestModel.Property))] + public TestModel Model { get; } + } + + public class GH0473ViewModel_Expected : ViewModelBase + { + public GH0473ViewModel_Expected(TestModel testModel) + { + ArgumentNullException.ThrowIfNull(testModel); + + Model = testModel; + } + + [Model(SupportIEditableObject = false, SupportValidation = false)] + public TestModel Model + { + get { return GetValue(ModelProperty); } + set { SetValue(ModelProperty, value); } + } + +#if CATEL_5 + public static readonly PropertyData ModelProperty = RegisterProperty(nameof(Model), typeof(TestModel), null); +#else + public static readonly IPropertyData ModelProperty = RegisterProperty(nameof(Model), typeof(TestModel), null); +#endif + + [ViewModelToModel("Model", "Property")] + public object Property + { + get { return GetValue(PropertyProperty); } + set { SetValue(PropertyProperty, value); } + } + +#if CATEL_5 + public static readonly PropertyData PropertyProperty = RegisterProperty(nameof(Property), typeof(object), null); +#else + public static readonly IPropertyData PropertyProperty = RegisterProperty(nameof(Property), typeof(object), null); +#endif + } + + public class TestModel + { + public object Property { get; set; } + } +} diff --git a/src/Catel.Fody.TestAssembly.Shared/CSharp6.AutoPropertyInitializer.cs b/src/Catel.Fody.TestAssembly.Shared/CSharp6.AutoPropertyInitializer.cs index c239666c..b3b05f43 100644 --- a/src/Catel.Fody.TestAssembly.Shared/CSharp6.AutoPropertyInitializer.cs +++ b/src/Catel.Fody.TestAssembly.Shared/CSharp6.AutoPropertyInitializer.cs @@ -6,9 +6,7 @@ public class CSharp6_AutoPropertyInitializer : ModelBase { - #region Properties public ObservableCollection SimpleModels { get; set; } = new ObservableCollection(); - #endregion } public class CSharp6_AutoPropertyInitializerWithMultipleConstructors : ModelBase @@ -23,9 +21,7 @@ public CSharp6_AutoPropertyInitializerWithMultipleConstructors(int someValue) } - #region Properties public bool ShowErrors { get; set; } = true; - #endregion } public class CSharp6_AutoPropertyInitializer_Generic : ModelBase @@ -40,11 +36,9 @@ public CSharp6_AutoPropertyInitializer_Generic(Guid guid) } - #region Properties public ObservableCollection SimpleModels { get; set; } = new ObservableCollection(); public T SelectedItem { get; set; } = default(T); - #endregion } public class CSharp6_AutoPropertyInitializer_Generic : CSharp6_AutoPropertyInitializer_Generic @@ -83,6 +77,13 @@ public CSharp6_AutoPropertyInitializer_Generic_ExpectedCode() SelectedItem = default(T); } + public CSharp6_AutoPropertyInitializer_Generic_ExpectedCode(Guid guid) + { + SimpleModels_Field = new ObservableCollection(); + SimpleModels_Property = new ObservableCollection(); + SelectedItem = default(T); + } + public ObservableCollection SimpleModels_Field; public ObservableCollection SimpleModels_Property { get; set; } @@ -93,5 +94,12 @@ public CSharp6_AutoPropertyInitializer_Generic_ExpectedCode() [NoWeaving] public class CSharp6_AutoPropertyInitializer_Generic_ExpectedCode : CSharp6_AutoPropertyInitializer_Generic_ExpectedCode { + public CSharp6_AutoPropertyInitializer_Generic_ExpectedCode() + : base(Guid.NewGuid()) + { + + } + + public string AdditionalProperty { get; set; } } } diff --git a/src/Catel.Fody.TestAssembly.Shared/DefaultValueModel.cs b/src/Catel.Fody.TestAssembly.Shared/DefaultValueModel.cs index c9039735..6607c66a 100644 --- a/src/Catel.Fody.TestAssembly.Shared/DefaultValueModel.cs +++ b/src/Catel.Fody.TestAssembly.Shared/DefaultValueModel.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System.ComponentModel; using Catel.Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/DependentPropertyModel.cs b/src/Catel.Fody.TestAssembly.Shared/DependentPropertyModel.cs index 25bbbf65..ab99c31e 100644 --- a/src/Catel.Fody.TestAssembly.Shared/DependentPropertyModel.cs +++ b/src/Catel.Fody.TestAssembly.Shared/DependentPropertyModel.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System.Collections.Generic; using Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/ExposingViewModel.cs b/src/Catel.Fody.TestAssembly.Shared/ExposingViewModel.cs index 79de5676..8876faf2 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ExposingViewModel.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ExposingViewModel.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System.ComponentModel; using Catel.Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/GenericPropertyModel.cs b/src/Catel.Fody.TestAssembly.Shared/GenericPropertyModel.cs index 518d15e3..f7475184 100644 --- a/src/Catel.Fody.TestAssembly.Shared/GenericPropertyModel.cs +++ b/src/Catel.Fody.TestAssembly.Shared/GenericPropertyModel.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System; using Catel.Data; @@ -34,7 +27,6 @@ public GenericPropertyModelAsObject() public class GenericPropertyModel : ModelBase { - #region Properties public TModel MyModel { get; set; } /// @@ -49,8 +41,7 @@ public TModel MyModelCatel #if CATEL_5 public static readonly PropertyData MyModelCatelProperty = RegisterProperty("MyModelCatel", typeof(TModel), null); #elif CATEL_6 - public static readonly IPropertyData MyModelCatelProperty = RegisterProperty("MyModelCatel", typeof(TModel), null); + public static readonly IPropertyData MyModelCatelProperty = RegisterProperty("MyModelCatel", null); #endif - #endregion } } diff --git a/src/Catel.Fody.TestAssembly.Shared/GlobalSuppressions.cs b/src/Catel.Fody.TestAssembly.Shared/GlobalSuppressions.cs new file mode 100644 index 00000000..4e55fdcf --- /dev/null +++ b/src/Catel.Fody.TestAssembly.Shared/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Catel.Analyzers.Core", "CTL0008:Use ArgumentNullException.ThrowIfNull for argument check", Justification = "")] diff --git a/src/Catel.Fody.TestAssembly.Shared/Inheritance.cs b/src/Catel.Fody.TestAssembly.Shared/Inheritance.cs index 147c6492..e183b3a0 100644 --- a/src/Catel.Fody.TestAssembly.Shared/Inheritance.cs +++ b/src/Catel.Fody.TestAssembly.Shared/Inheritance.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2012 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/LoggingClass.cs b/src/Catel.Fody.TestAssembly.Shared/LoggingClass.cs index 4582b12f..4e865aa4 100644 --- a/src/Catel.Fody.TestAssembly.Shared/LoggingClass.cs +++ b/src/Catel.Fody.TestAssembly.Shared/LoggingClass.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Logging; diff --git a/src/Catel.Fody.TestAssembly.Shared/ModelBaseTest.cs b/src/Catel.Fody.TestAssembly.Shared/ModelBaseTest.cs index 79ee5c1d..a8c4ac06 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ModelBaseTest.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ModelBaseTest.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2012 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using System; using System.Collections.ObjectModel; @@ -22,7 +16,7 @@ public ObservableCollection CatelOperations public static readonly PropertyData CatelOperationsProperty = RegisterProperty("CatelOperations", typeof(ObservableCollection), null, (sender, e) => ((GenericModelBaseTestBase)sender).OnCatelOperationsChanged()); #elif CATEL_6 - public static readonly IPropertyData CatelOperationsProperty = RegisterProperty("CatelOperations", typeof(ObservableCollection), null, + public static readonly IPropertyData CatelOperationsProperty = RegisterProperty>("CatelOperations", () => null, (sender, e) => ((GenericModelBaseTestBase)sender).OnCatelOperationsChanged()); #endif @@ -83,7 +77,7 @@ public string FullName #if CATEL_5 public static readonly PropertyData FullNameProperty = RegisterProperty("FullName", typeof(string), string.Empty); #elif CATEL_6 - public static readonly IPropertyData FullNameProperty = RegisterProperty("FullName", typeof(string), string.Empty); + public static readonly IPropertyData FullNameProperty = RegisterProperty("FullName", string.Empty); #endif public string FullNameWithChangeCallback { get; set; } diff --git a/src/Catel.Fody.TestAssembly.Shared/ModelWithDoubleValues.cs b/src/Catel.Fody.TestAssembly.Shared/ModelWithDoubleValues.cs index 56c3f75c..fe328049 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ModelWithDoubleValues.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ModelWithDoubleValues.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Catel.Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/MyViewModelBase.cs b/src/Catel.Fody.TestAssembly.Shared/MyViewModelBase.cs index fc0ac088..c82f2858 100644 --- a/src/Catel.Fody.TestAssembly.Shared/MyViewModelBase.cs +++ b/src/Catel.Fody.TestAssembly.Shared/MyViewModelBase.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2012 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { public class MyViewModelBase : MVVM.ViewModelBase { diff --git a/src/Catel.Fody.TestAssembly.Shared/NoWeavingModelTest.cs b/src/Catel.Fody.TestAssembly.Shared/NoWeavingModelTest.cs index eda16fa0..89b6c017 100644 --- a/src/Catel.Fody.TestAssembly.Shared/NoWeavingModelTest.cs +++ b/src/Catel.Fody.TestAssembly.Shared/NoWeavingModelTest.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Catel.Data; diff --git a/src/Catel.Fody.TestAssembly.Shared/ObservableObjectTest.cs b/src/Catel.Fody.TestAssembly.Shared/ObservableObjectTest.cs index dbcf3e6a..2f357c8b 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ObservableObjectTest.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ObservableObjectTest.cs @@ -84,7 +84,7 @@ public bool IsExpanded } _isExpanded = value; - if (RowGroupDefinition == null) + if (RowGroupDefinition is null) { RaisePropertyChanged(propertyExpression: () => IsExpanded); @@ -223,7 +223,7 @@ public bool IsExpanded } _isExpanded = value; - if (RowGroupDefinition == null) + if (RowGroupDefinition is null) { RaisePropertyChanged("IsExpanded"); diff --git a/src/Catel.Fody.TestAssembly.Shared/ViewModelBaseTest.cs b/src/Catel.Fody.TestAssembly.Shared/ViewModelBaseTest.cs index 41b97b94..d657903d 100644 --- a/src/Catel.Fody.TestAssembly.Shared/ViewModelBaseTest.cs +++ b/src/Catel.Fody.TestAssembly.Shared/ViewModelBaseTest.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2012 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using Data; using MVVM; diff --git a/src/Catel.Fody.TestExternalTypesAssembly.Catel5/Catel.Fody.TestExternalTypesAssembly.Catel5.csproj b/src/Catel.Fody.TestExternalTypesAssembly.Catel5/Catel.Fody.TestExternalTypesAssembly.Catel5.csproj index f29b8db2..67bc2cfc 100644 --- a/src/Catel.Fody.TestExternalTypesAssembly.Catel5/Catel.Fody.TestExternalTypesAssembly.Catel5.csproj +++ b/src/Catel.Fody.TestExternalTypesAssembly.Catel5/Catel.Fody.TestExternalTypesAssembly.Catel5.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.TestExternalTypesAssembly.Catel5 Catel.Fody.TestExternalTypesAssembly en-US @@ -14,11 +14,7 @@ - - - - - + diff --git a/src/Catel.Fody.TestExternalTypesAssembly.Catel6/Catel.Fody.TestExternalTypesAssembly.Catel6.csproj b/src/Catel.Fody.TestExternalTypesAssembly.Catel6/Catel.Fody.TestExternalTypesAssembly.Catel6.csproj index f0c5885e..4350b3e2 100644 --- a/src/Catel.Fody.TestExternalTypesAssembly.Catel6/Catel.Fody.TestExternalTypesAssembly.Catel6.csproj +++ b/src/Catel.Fody.TestExternalTypesAssembly.Catel6/Catel.Fody.TestExternalTypesAssembly.Catel6.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.TestExternalTypesAssembly.Catel6 Catel.Fody.TestExternalTypesAssembly en-US @@ -14,11 +14,7 @@ - - - - - + diff --git a/src/Catel.Fody.TestExternalTypesAssembly.Shared/ExternalType.cs b/src/Catel.Fody.TestExternalTypesAssembly.Shared/ExternalType.cs index 851381f7..7729dcd3 100644 --- a/src/Catel.Fody.TestExternalTypesAssembly.Shared/ExternalType.cs +++ b/src/Catel.Fody.TestExternalTypesAssembly.Shared/ExternalType.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.ObjectModel; using Catel.Data; diff --git a/src/Catel.Fody.Tests.Catel5/Catel.Fody.Tests.Catel5.csproj b/src/Catel.Fody.Tests.Catel5/Catel.Fody.Tests.Catel5.csproj index d7d42c62..9522225d 100644 --- a/src/Catel.Fody.Tests.Catel5/Catel.Fody.Tests.Catel5.csproj +++ b/src/Catel.Fody.Tests.Catel5/Catel.Fody.Tests.Catel5.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.Tests.Catel5 Catel.Fody.Tests en-US @@ -14,17 +14,16 @@ - + - - - - + + + + - - + diff --git a/src/Catel.Fody.Tests.Catel6/Catel.Fody.Tests.Catel6.csproj b/src/Catel.Fody.Tests.Catel6/Catel.Fody.Tests.Catel6.csproj index dff36e42..9ab2188c 100644 --- a/src/Catel.Fody.Tests.Catel6/Catel.Fody.Tests.Catel6.csproj +++ b/src/Catel.Fody.Tests.Catel6/Catel.Fody.Tests.Catel6.csproj @@ -1,6 +1,6 @@  - net5.0-windows + net6.0-windows Catel.Fody.Tests.Catel6 Catel.Fody.Tests en-US @@ -14,17 +14,16 @@ - + - - - - + + + + - - + diff --git a/src/Catel.Fody.Tests.Shared/ArgumentFacts.cs b/src/Catel.Fody.Tests.Shared/ArgumentFacts.cs index 397302b3..8de66a6a 100644 --- a/src/Catel.Fody.Tests.Shared/ArgumentFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ArgumentFacts.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.Threading; diff --git a/src/Catel.Fody.Tests.Shared/ArgumentFacts.expressions.cs b/src/Catel.Fody.Tests.Shared/ArgumentFacts.expressions.cs index f77e810e..478c98ab 100644 --- a/src/Catel.Fody.Tests.Shared/ArgumentFacts.expressions.cs +++ b/src/Catel.Fody.Tests.Shared/ArgumentFacts.expressions.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.Collections; diff --git a/src/Catel.Fody.Tests.Shared/AssemblyWeaver.cs b/src/Catel.Fody.Tests.Shared/AssemblyWeaver.cs index 4173887c..0edd9629 100644 --- a/src/Catel.Fody.Tests.Shared/AssemblyWeaver.cs +++ b/src/Catel.Fody.Tests.Shared/AssemblyWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; @@ -17,15 +10,12 @@ public class AssemblyWeaver { - #region Constants public Assembly Assembly; public string BeforeAssemblyPath; public string AfterAssemblyPath; public List Errors = new List(); - #endregion - #region Constructors static AssemblyWeaver() { var catelVersion = "unknown"; @@ -36,7 +26,9 @@ static AssemblyWeaver() catelVersion = "6"; #endif +#if CATEL_5 Instance_NetStandard = new AssemblyWeaver($"Catel.Fody.TestAssembly.NetStandard.Catel{catelVersion}.dll"); +#endif Instance = new AssemblyWeaver($"Catel.Fody.TestAssembly.Catel{catelVersion}.dll"); } @@ -111,16 +103,15 @@ public AssemblyWeaver(string assemblyLocation, List referenceAssemblyPat Assembly = Assembly.LoadFile(AfterAssemblyPath); } - #endregion public static AssemblyWeaver Instance { get; private set; } +#if CATEL_5 public static AssemblyWeaver Instance_NetStandard { get; private set; } +#endif - #region Methods private void LogError(string error) { Errors.Add(error); } - #endregion } diff --git a/src/Catel.Fody.Tests.Shared/ConfigurationFacts.cs b/src/Catel.Fody.Tests.Shared/ConfigurationFacts.cs index c0406be8..f81b3abd 100644 --- a/src/Catel.Fody.Tests.Shared/ConfigurationFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ConfigurationFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2014 - 2014 CatenaLogic. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System.Xml.Linq; using Fody; diff --git a/src/Catel.Fody.Tests.Shared/DefaultValueFacts.cs b/src/Catel.Fody.Tests.Shared/DefaultValueFacts.cs index f4a517da..18c5869d 100644 --- a/src/Catel.Fody.Tests.Shared/DefaultValueFacts.cs +++ b/src/Catel.Fody.Tests.Shared/DefaultValueFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using Data; diff --git a/src/Catel.Fody.Tests.Shared/DependentPropertyFacts.cs b/src/Catel.Fody.Tests.Shared/DependentPropertyFacts.cs index 68bd8c00..35cacee7 100644 --- a/src/Catel.Fody.Tests.Shared/DependentPropertyFacts.cs +++ b/src/Catel.Fody.Tests.Shared/DependentPropertyFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.Collections.Generic; @@ -34,7 +27,7 @@ public void NotifiesPropertyChangedOfDependentProperties(string modelType, strin propertyInfo.SetValue(instance, newValue); var isPropertyChangedWorkingPropertyInfo = instance.GetType().GetProperty("IsPropertyChangedWorking"); - if (isPropertyChangedWorkingPropertyInfo != null) + if (isPropertyChangedWorkingPropertyInfo is not null) { Assert.IsTrue((bool)isPropertyChangedWorkingPropertyInfo.GetValue(instance)); } diff --git a/src/Catel.Fody.Tests.Shared/ExposeFacts.cs b/src/Catel.Fody.Tests.Shared/ExposeFacts.cs index 7546d5a4..f068a26d 100644 --- a/src/Catel.Fody.Tests.Shared/ExposeFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ExposeFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using Data; @@ -58,7 +51,7 @@ public void CanCreateReadOnlyExposedProperties() var propertyInfo = viewModelType.GetPropertyEx("ReadOnlyProperty"); var setMethod = propertyInfo.GetSetMethod(true); - if (setMethod != null) + if (setMethod is not null) { Assert.IsFalse(setMethod.IsPublic); } diff --git a/src/Catel.Fody.Tests.Shared/Helpers/AssemblyDirectoryHelper.cs b/src/Catel.Fody.Tests.Shared/Helpers/AssemblyDirectoryHelper.cs index 5818874a..d7b0f05b 100644 --- a/src/Catel.Fody.Tests.Shared/Helpers/AssemblyDirectoryHelper.cs +++ b/src/Catel.Fody.Tests.Shared/Helpers/AssemblyDirectoryHelper.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; diff --git a/src/Catel.Fody.Tests.Shared/Helpers/ExceptionTester.cs b/src/Catel.Fody.Tests.Shared/Helpers/ExceptionTester.cs index 997a9b20..387657b9 100644 --- a/src/Catel.Fody.Tests.Shared/Helpers/ExceptionTester.cs +++ b/src/Catel.Fody.Tests.Shared/Helpers/ExceptionTester.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2018 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; @@ -28,7 +21,7 @@ public static void CallMethodAndExpectException(Action action) return; } - if (ex.InnerException != null) + if (ex.InnerException is not null) { exceptionType = ex.InnerException.GetType(); } diff --git a/src/Catel.Fody.Tests.Shared/InheritanceFacts.cs b/src/Catel.Fody.Tests.Shared/InheritanceFacts.cs index 99dcb4e8..58b0adc3 100644 --- a/src/Catel.Fody.Tests.Shared/InheritanceFacts.cs +++ b/src/Catel.Fody.Tests.Shared/InheritanceFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/LoggingFacts.cs b/src/Catel.Fody.Tests.Shared/LoggingFacts.cs index 346098dd..a4ee4e24 100644 --- a/src/Catel.Fody.Tests.Shared/LoggingFacts.cs +++ b/src/Catel.Fody.Tests.Shared/LoggingFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/ModelBaseFacts.cs b/src/Catel.Fody.Tests.Shared/ModelBaseFacts.cs index 7c65adee..56a81655 100644 --- a/src/Catel.Fody.Tests.Shared/ModelBaseFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ModelBaseFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.Collections.ObjectModel; diff --git a/src/Catel.Fody.Tests.Shared/ModelWithDoubleValuesFacts.cs b/src/Catel.Fody.Tests.Shared/ModelWithDoubleValuesFacts.cs index 16b53d18..870e9ac1 100644 --- a/src/Catel.Fody.Tests.Shared/ModelWithDoubleValuesFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ModelWithDoubleValuesFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/NoWeavingFacts.cs b/src/Catel.Fody.Tests.Shared/NoWeavingFacts.cs index c29eb52a..c3ebb842 100644 --- a/src/Catel.Fody.Tests.Shared/NoWeavingFacts.cs +++ b/src/Catel.Fody.Tests.Shared/NoWeavingFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using Data; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/PeVerifyFacts.cs b/src/Catel.Fody.Tests.Shared/PeVerifyFacts.cs index eb64f670..5f85c1df 100644 --- a/src/Catel.Fody.Tests.Shared/PeVerifyFacts.cs +++ b/src/Catel.Fody.Tests.Shared/PeVerifyFacts.cs @@ -1,12 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -#pragma warning disable 618 -namespace Catel.Fody.TestAssembly +namespace Catel.Fody.TestAssembly { using global::Fody; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/Repros/CTL504.cs b/src/Catel.Fody.Tests.Shared/Repros/CTL504.cs index c5609258..38b248ee 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/CTL504.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/CTL504.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/Repros/CTL569.cs b/src/Catel.Fody.Tests.Shared/Repros/CTL569.cs index bc0792e7..9ef12eba 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/CTL569.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/CTL569.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2015 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.ComponentModel; diff --git a/src/Catel.Fody.Tests.Shared/Repros/CTL768.cs b/src/Catel.Fody.Tests.Shared/Repros/CTL768.cs index 7e52ad19..851e9fb4 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/CTL768.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/CTL768.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2015 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using System.ComponentModel; diff --git a/src/Catel.Fody.Tests.Shared/Repros/CTL908.cs b/src/Catel.Fody.Tests.Shared/Repros/CTL908.cs index 97ac742e..7617ede8 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/CTL908.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/CTL908.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2016 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0008.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0008.cs index cd9fdbfb..81f2b00c 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/GH0008.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0008.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2016 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using Catel.Services; diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0012.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0012.cs index 81c83dd1..9f221796 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/GH0012.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0012.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2016 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0021.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0021.cs index 1cc93c9b..457794b5 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/GH0021.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0021.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2018 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests.Repros +namespace Catel.Fody.Tests.Repros { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0295.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0295.cs index 3806a28d..11b1b417 100644 --- a/src/Catel.Fody.Tests.Shared/Repros/GH0295.cs +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0295.cs @@ -1,4 +1,6 @@ -namespace Catel.Fody.Tests.Repros +#if CATEL_5 + +namespace Catel.Fody.Tests.Repros { using System; using NUnit.Framework; @@ -21,3 +23,5 @@ public void NetStandardWeaving() } } } + +#endif diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0361.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0361.cs new file mode 100644 index 00000000..a63eb113 --- /dev/null +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0361.cs @@ -0,0 +1,18 @@ +namespace Catel.Fody.Tests.Repros +{ + using System; + using NUnit.Framework; + + [TestFixture] + public class GH0361TestFixture + { + [TestCase] + public void WeavingWithSetValueMethodInViewModel() + { + var viewModelType = AssemblyWeaver.Instance.Assembly.GetType("Catel.Fody.TestAssembly.Bugs.GH0361.MyDerivedViewModel"); + var viewModel = Activator.CreateInstance(viewModelType) as dynamic; + + viewModel.Property = new object(); + } + } +} diff --git a/src/Catel.Fody.Tests.Shared/Repros/GH0473.cs b/src/Catel.Fody.Tests.Shared/Repros/GH0473.cs new file mode 100644 index 00000000..4c135f04 --- /dev/null +++ b/src/Catel.Fody.Tests.Shared/Repros/GH0473.cs @@ -0,0 +1,39 @@ +namespace Catel.Fody.Tests.Repros +{ + using System; + using System.ComponentModel; + using Catel.MVVM; + using Catel.Reflection; + using NUnit.Framework; + + [TestFixture] + public class GH0473TestFixture + { + [TestCase] + public void Weaving_Init_Only_Model_Properties() + { + var modelType = AssemblyWeaver.Instance.Assembly.GetType("Catel.Fody.TestAssembly.Bugs.GH0473.TestModel"); + var model = Activator.CreateInstance(modelType); + + var viewModelType = AssemblyWeaver.Instance.Assembly.GetType("Catel.Fody.TestAssembly.Bugs.GH0473.GH0473ViewModel"); + var viewModel = Activator.CreateInstance(viewModelType, model) as dynamic; + + viewModel.Property = new object(); + + var isCalled = false; + + var vm = (ViewModelBase)viewModel; + vm.PropertyChanged += (sender, e) => + { + if (e.HasPropertyChanged("Model")) + { + isCalled = true; + } + }; + + PropertyHelper.SetPropertyValue(viewModel, "Model", null); + + Assert.IsTrue(isCalled); + } + } +} diff --git a/src/Catel.Fody.Tests.Shared/TestClasses/MyEventArgs.cs b/src/Catel.Fody.Tests.Shared/TestClasses/MyEventArgs.cs index dc9bcb9e..09dde947 100644 --- a/src/Catel.Fody.Tests.Shared/TestClasses/MyEventArgs.cs +++ b/src/Catel.Fody.Tests.Shared/TestClasses/MyEventArgs.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; diff --git a/src/Catel.Fody.Tests.Shared/ViewModelBaseFacts.cs b/src/Catel.Fody.Tests.Shared/ViewModelBaseFacts.cs index 965de58b..fba0683b 100644 --- a/src/Catel.Fody.Tests.Shared/ViewModelBaseFacts.cs +++ b/src/Catel.Fody.Tests.Shared/ViewModelBaseFacts.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Tests +namespace Catel.Fody.Tests { using System; using NUnit.Framework; diff --git a/src/Catel.Fody.sln b/src/Catel.Fody.sln index 8d2c9ea2..67b0018f 100644 --- a/src/Catel.Fody.sln +++ b/src/Catel.Fody.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28809.33 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33209.295 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catel.Fody", "Catel.Fody\Catel.Fody.csproj", "{0B8FEB0F-84FE-425D-BF0D-D00D52BA6BA5}" EndProject @@ -46,8 +46,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catel.Fody.TestAssembly.Cat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catel.Fody.TestAssembly.NetStandard.Catel5", "Catel.Fody.TestAssembly.NetStandard.Catel5\Catel.Fody.TestAssembly.NetStandard.Catel5.csproj", "{BEA9E01A-9C36-43A6-BB89-ED85A191ADD0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catel.Fody.TestAssembly.NetStandard.Catel6", "Catel.Fody.TestAssembly.NetStandard.Catel6\Catel.Fody.TestAssembly.NetStandard.Catel6.csproj", "{96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -109,12 +107,6 @@ Global {BEA9E01A-9C36-43A6-BB89-ED85A191ADD0}.Release|Any CPU.Build.0 = Release|Any CPU {BEA9E01A-9C36-43A6-BB89-ED85A191ADD0}.Test|Any CPU.ActiveCfg = Debug|Any CPU {BEA9E01A-9C36-43A6-BB89-ED85A191ADD0}.Test|Any CPU.Build.0 = Debug|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Release|Any CPU.Build.0 = Release|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Test|Any CPU.ActiveCfg = Debug|Any CPU - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5}.Test|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -133,7 +125,6 @@ Global {2046F93A-E20A-4CC9-8721-00EC27C01915} = {CCF3EB63-3689-4699-BF21-04C28B53DF62} {ADBE4D28-6090-44D9-AEBC-62E404FDFE56} = {CCF3EB63-3689-4699-BF21-04C28B53DF62} {BEA9E01A-9C36-43A6-BB89-ED85A191ADD0} = {945DAB30-25E0-4A99-834A-AA32D81E6FCE} - {96E63FEE-DCE2-48D5-8D0D-6B25AA3E35A5} = {CCF3EB63-3689-4699-BF21-04C28B53DF62} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B8FBD666-DAD3-4467-90B2-A3D54DA5FE4D} diff --git a/src/Catel.Fody/Catel.Fody.csproj b/src/Catel.Fody/Catel.Fody.csproj index e24a973b..8789768f 100644 --- a/src/Catel.Fody/Catel.Fody.csproj +++ b/src/Catel.Fody/Catel.Fody.csproj @@ -32,8 +32,7 @@ - - + diff --git a/src/Catel.Fody/CatelVersion.cs b/src/Catel.Fody/CatelVersion.cs index 3abbe9be..2e43fb47 100644 --- a/src/Catel.Fody/CatelVersion.cs +++ b/src/Catel.Fody/CatelVersion.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { public enum CatelVersion { diff --git a/src/Catel.Fody/Configuration.cs b/src/Catel.Fody/Configuration.cs index 90e5621d..8a325135 100644 --- a/src/Catel.Fody/Configuration.cs +++ b/src/Catel.Fody/Configuration.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Xml.Linq; diff --git a/src/Catel.Fody/Core/CatelTypeNodeBuilder.cs b/src/Catel.Fody/Core/CatelTypeNodeBuilder.cs index 9acf2fbd..fda34b80 100644 --- a/src/Catel.Fody/Core/CatelTypeNodeBuilder.cs +++ b/src/Catel.Fody/Core/CatelTypeNodeBuilder.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.Generic; using System.Linq; diff --git a/src/Catel.Fody/Core/CodeGenTypeCleaner.cs b/src/Catel.Fody/Core/CodeGenTypeCleaner.cs index 08cdf6ec..88ce653d 100644 --- a/src/Catel.Fody/Core/CodeGenTypeCleaner.cs +++ b/src/Catel.Fody/Core/CodeGenTypeCleaner.cs @@ -1,9 +1,3 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - namespace Catel.Fody { using System.Collections.Generic; diff --git a/src/Catel.Fody/Core/ModelBasePropertyWeaver.cs b/src/Catel.Fody/Core/ModelBasePropertyWeaver.cs index 987544c6..fcb4f2ea 100644 --- a/src/Catel.Fody/Core/ModelBasePropertyWeaver.cs +++ b/src/Catel.Fody/Core/ModelBasePropertyWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; @@ -41,7 +34,7 @@ public void Execute(bool force = false) var property = _propertyData.PropertyDefinition; if (property is null) { - FodyEnvironment.WriteWarning("Skipping an unknown property because it has no property definition"); + FodyEnvironment.WriteWarning($"\t{_propertyData.Name} Skipping an unknown property because it has no property definition"); return; } @@ -317,12 +310,12 @@ private bool AddPropertyRegistration(PropertyDefinition property, CatelTypePrope select instruction).FirstOrDefault(); var exceptionHandler = body.ExceptionHandlers.FirstOrDefault(); - if (exceptionHandler != null) + if (exceptionHandler is not null) { instructionToInsert = exceptionHandler.TryStart; } - var index = (instructionToInsert != null) ? instructions.IndexOf(instructionToInsert) : instructions.Count; + var index = (instructionToInsert is not null) ? instructions.IndexOf(instructionToInsert) : instructions.Count; var instructionsToInsert = new List(); @@ -433,7 +426,7 @@ private List CreatePropertyRegistration_Catel5(PropertyDefinition p instructions.AddRange(CreateDefaultValueInstructions(propertyData)); - if (propertyData.ChangeCallbackReference != null) + if (propertyData.ChangeCallbackReference is not null) { instructions.AddRange(CreateChangeCallbackReference_Catel5(property)); } @@ -467,7 +460,7 @@ private List CreatePropertyRegistration_Catel6(PropertyDefinition p instructions.AddRange(CreateDefaultValueInstructions(propertyData)); - if (propertyData.ChangeCallbackReference != null) + if (propertyData.ChangeCallbackReference is not null) { instructions.AddRange(CreateChangeCallbackReference_Catel6(property)); } @@ -526,7 +519,7 @@ private List CreateDefaultValueInstructions(CatelTypeProperty prope { instructions.Add(Instruction.Create(OpCodes.Ldc_R8, doubleValue)); } - else if (resolvedPropertyType != null && resolvedPropertyType.IsEnum && propertyData.DefaultValue != null) + else if (resolvedPropertyType is not null && resolvedPropertyType.IsEnum && propertyData.DefaultValue is not null) { instructions.Add(Instruction.Create(OpCodes.Ldc_I4, (int)((CustomAttributeArgument)propertyData.DefaultValue).Value)); } @@ -808,7 +801,7 @@ private void RemoveBackingField(PropertyDefinition property) var declaringType = property.DeclaringType; var field = GetFieldDefinition(declaringType, fieldName, false); - if (field != null) + if (field is not null) { foreach (var ctor in declaringType.GetConstructors()) { @@ -835,6 +828,18 @@ private void RemoveBackingField(PropertyDefinition property) if (instruction.IsOpCode(OpCodes.Stfld)) { + // Replace + // + // IL_0014: ldarg.0 + // IL_0015: ldarg.1 + // IL_0016: stfld class Catel.Fody.TestAssembly.Bugs.GH0473.TestModel Catel.Fody.TestAssembly.Bugs.GH0473.GH0473ViewModel::'k__BackingField' /* 04000097 */ + // + // with + // + // IL_0014: ldarg.0 + // IL_0015: ldarg.1 + // IL_0016: call instance void Catel.Fody.TestAssembly.Bugs.GH0473.GH0473ViewModel_Expected::set_Model(class Catel.Fody.TestAssembly.Bugs.GH0473.TestModel) /* 06000205 */ + // Setter instruction.OpCode = OpCodes.Call; @@ -849,7 +854,7 @@ private void RemoveBackingField(PropertyDefinition property) // Now move this to the end of the method (we need to call the base ctor first to have the property bag ready) var baseIndex = ctor.FindBaseConstructorIndex(); - if (baseIndex >= 0) + if (baseIndex > i) { // After a call to a ctor, a double nop is required var indexToInsert = baseIndex + 1; @@ -882,7 +887,7 @@ private void RemoveBackingField(PropertyDefinition property) // Now move this to the end of the method (we need to call the base ctor first to have the property bag ready) var baseIndex = ctor.FindBaseConstructorIndex(); - if (baseIndex >= 0) + if (baseIndex > i) { // After a call to a ctor, a double nop is required var indexToInsert = baseIndex + 1; @@ -945,12 +950,20 @@ private void RemoveBackingField(PropertyDefinition property) instructions.RemoveAt(i - 1); } + var indexToInsert = i + 1; + // Now move this to the end of the method (we need to call the base ctor first to have the property bag ready) var baseIndex = ctor.FindBaseConstructorIndex(); - if (baseIndex >= 0) + if (baseIndex < 0) + { + FodyEnvironment.WriteError($"Field '{declaringType.FullName}.{field.Name}' is used in ctor '{ctor}'. A rare condition occurred (no base ctor found), please contact support"); + continue; + } + + if (baseIndex > i) { // After a call to a ctor, a double nop is required - var indexToInsert = baseIndex + 1; + indexToInsert = baseIndex + 1; if (instructions.IsNextInstructionOpCode(baseIndex, OpCodes.Nop)) { indexToInsert++; @@ -960,13 +973,9 @@ private void RemoveBackingField(PropertyDefinition property) indexToInsert++; } } - - instructions.Insert(indexToInsert, newInstructions); - } - else - { - FodyEnvironment.WriteError($"Field '{declaringType.FullName}.{field.Name}' is used in ctor '{ctor}'. A rare condition occurred (no base ctor found), please contact support"); } + + instructions.Insert(indexToInsert, newInstructions); } else { diff --git a/src/Catel.Fody/Core/Models/CatelType.cs b/src/Catel.Fody/Core/Models/CatelType.cs index b95852e0..071f66b9 100644 --- a/src/Catel.Fody/Core/Models/CatelType.cs +++ b/src/Catel.Fody/Core/Models/CatelType.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; @@ -193,6 +187,7 @@ public IEnumerable AllProperties { var typeDefinition = TypeDefinition; var propertyDefinitions = new List(); + while (typeDefinition.BaseType.FullName != "System.Object") { propertyDefinitions.AddRange(typeDefinition.Properties.ToList()); @@ -248,7 +243,7 @@ private bool DetermineMethods() // Introduced in Catel 5.12 / 6.0 var genericSetValue = RecursiveFindMethod(TypeDefinition, "SetValue", parameterNames, true); - if (genericSetValue != null) + if (genericSetValue is not null) { SetValueGenericInvoker = module.ImportReference(genericSetValue); } @@ -269,9 +264,25 @@ private void DetermineProperties() typeProperty.RemoveAttribute("NoWeavingAttribute"); NoWeavingProperties.Add(typeProperty); } - else if (typeProperty.SetMethod != null && !typeProperty.SetMethod.IsStatic) + else if (!(typeProperty.SetMethod?.IsStatic ?? false)) { - Properties.Add(new CatelTypeProperty(TypeDefinition, typeProperty)); + // If there is no set method, this is an init only property. The weaver + // should only weave when decorated with Model or Expose attributes + var isInitOnlyProperty = typeProperty.SetMethod is null; + if (isInitOnlyProperty) + { + if (!typeProperty.IsDecoratedWithAttribute("ModelAttribute") && + !typeProperty.IsDecoratedWithAttribute("ExposeAttribute")) + { + // Leave init-only + continue; + } + } + + Properties.Add(new CatelTypeProperty(TypeDefinition, typeProperty) + { + IsInitOnlyProperty = isInitOnlyProperty + }); } } } @@ -423,14 +434,14 @@ private bool FindMethodDefinition(TypeDefinition type, string methodName, string select method).ToList(); } - if (parameterNames != null) + if (parameterNames is not null) { methodDefinitions = methodDefinitions.Where(x => x.Parameters.Select(y => y.Name).ToArray().SequenceEqual(parameterNames)).ToList(); } methodDefinition = methodDefinitions.FirstOrDefault(); - return methodDefinition != null; + return methodDefinition is not null; } public IEnumerable GetDependentPropertiesFrom(PropertyDefinition property) @@ -461,7 +472,7 @@ public bool ExistPropertyDependencyBetween(PropertyDefinition dependentPropertyD var found = false; var getMethodDefinition = dependentPropertyDefinition?.GetMethod; - if (getMethodDefinition != null && getMethodDefinition.HasBody) + if (getMethodDefinition is not null && getMethodDefinition.HasBody) { var processor = getMethodDefinition.Body.GetILProcessor(); diff --git a/src/Catel.Fody/Core/Models/CatelTypeProperty.cs b/src/Catel.Fody/Core/Models/CatelTypeProperty.cs index e509500e..99ad840f 100644 --- a/src/Catel.Fody/Core/Models/CatelTypeProperty.cs +++ b/src/Catel.Fody/Core/Models/CatelTypeProperty.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Diagnostics; using System.Linq; @@ -27,10 +20,10 @@ public CatelTypeProperty(TypeDefinition typeDefinition, PropertyDefinition prope DetermineIncludeInBackup(); } - #region Fields public string Name { get; private set; } public bool IsReadOnly { get; set; } public bool IncludeInBackup { get; set; } + public bool IsInitOnlyProperty { get; set; } public TypeDefinition TypeDefinition { get; private set; } public PropertyDefinition PropertyDefinition { get; private set; } @@ -40,7 +33,6 @@ public CatelTypeProperty(TypeDefinition typeDefinition, PropertyDefinition prope public FieldDefinition BackingFieldDefinition { get; set; } public MethodReference ChangeCallbackReference { get; private set; } - #endregion private void DetermineFields() { BackingFieldDefinition = TryGetField(TypeDefinition, PropertyDefinition); @@ -58,7 +50,7 @@ private void DetermineMethods() foreach (var callbackReference in callbackReferences) { - if (callbackReference != null) + if (callbackReference is not null) { if (callbackReference.HasParameters) { @@ -80,19 +72,10 @@ private void DetermineMethods() private void DetermineDefaultValue() { - //var defaultValueAttribute = PropertyDefinition.GetAttribute("Catel.Fody.DefaultValueAttribute"); var defaultValueAttribute = PropertyDefinition.GetAttribute("System.ComponentModel.DefaultValueAttribute"); - if (defaultValueAttribute != null) + if (defaultValueAttribute is not null) { DefaultValue = defaultValueAttribute.ConstructorArguments[0].Value; - - // Catel.Fody attribute style - //var attributeValue = (CustomAttributeArgument) defaultValueAttribute.ConstructorArguments[0].Value; - //DefaultValue = attributeValue.Value; - - // Note: do not remove since we are now using System.ComponentModel.DefaultValueAttribute after - // the discussion at https://catelproject.atlassian.net/browse/CTL-244 - //PropertyDefinition.RemoveAttribute("Catel.Fody.DefaultValueAttribute"); } } @@ -101,7 +84,7 @@ private void DetermineIncludeInBackup() IncludeInBackup = true; var excludeFromBackupAttribute = PropertyDefinition.GetAttribute("Catel.Fody.ExcludeFromBackupAttribute"); - if (excludeFromBackupAttribute != null) + if (excludeFromBackupAttribute is not null) { IncludeInBackup = false; @@ -113,9 +96,10 @@ private static FieldDefinition TryGetField(TypeDefinition typeDefinition, Proper { var propertyName = property.Name; var fieldsWithSameType = typeDefinition.Fields.Where(x => x.DeclaringType == typeDefinition).ToList(); + foreach (var field in fieldsWithSameType) { - //AutoProp + // AutoProp if (field.Name == $"<{propertyName}>k__BackingField") { return field; @@ -131,22 +115,25 @@ private static FieldDefinition TryGetField(TypeDefinition typeDefinition, Proper { return field; } + //underScore if (fieldUpper == "_" + upperPropertyName) { return field; } } + return GetSingleField(property); } private static FieldDefinition GetSingleField(PropertyDefinition property) { var fieldDefinition = GetSingleField(property, Code.Stfld, property.SetMethod); - if (fieldDefinition != null) + if (fieldDefinition is not null) { return fieldDefinition; } + return GetSingleField(property, Code.Ldfld, property.GetMethod); } @@ -156,13 +143,14 @@ private static FieldDefinition GetSingleField(PropertyDefinition property, Code { return null; } + FieldReference fieldReference = null; foreach (var instruction in methodDefinition.Body.Instructions) { if (instruction.OpCode.Code == code) { //if fieldReference is not null then we are at the second one - if (fieldReference != null) + if (fieldReference is not null) { return null; } diff --git a/src/Catel.Fody/Core/Models/MemberMapping.cs b/src/Catel.Fody/Core/Models/MemberMapping.cs index 5030eeb3..0d5ce621 100644 --- a/src/Catel.Fody/Core/Models/MemberMapping.cs +++ b/src/Catel.Fody/Core/Models/MemberMapping.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using Mono.Cecil; diff --git a/src/Catel.Fody/Core/MsCoreReferenceFinder.cs b/src/Catel.Fody/Core/MsCoreReferenceFinder.cs index c388777c..52fe265e 100644 --- a/src/Catel.Fody/Core/MsCoreReferenceFinder.cs +++ b/src/Catel.Fody/Core/MsCoreReferenceFinder.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; @@ -39,8 +33,10 @@ public MsCoreReferenceFinder(ModuleWeaver moduleWeaver, IAssemblyResolver assemb public void Execute() { +#pragma warning disable IDISP001 // Dispose created var xmlDefinition = _assemblyResolver.Resolve("System.Xml"); - if (xmlDefinition != null) +#pragma warning restore IDISP001 // Dispose created + if (xmlDefinition is not null) { var xmlTypes = xmlDefinition.MainModule.Types; @@ -89,7 +85,9 @@ public TypeReference GetCoreTypeReference(string typeName) private IEnumerable GetTypes() { +#pragma warning disable IDISP001 // Dispose created var msCoreLibDefinition = _assemblyResolver.Resolve("mscorlib"); +#pragma warning restore IDISP001 // Dispose created var msCoreTypes = msCoreLibDefinition.MainModule.Types.Cast().ToList(); var objectDefinition = msCoreTypes.FirstOrDefault(x => string.Equals(x.Name, "Object")); @@ -165,8 +163,10 @@ private IEnumerable GetNetStandardTypes() foreach (var assembly in _moduleWeaver.ModuleDefinition.AssemblyReferences) { +#pragma warning disable IDISP001 // Dispose created var resolvedAssembly = _assemblyResolver.Resolve(assembly); - if ((resolvedAssembly != null) && resolvedAssembly.IsNetStandardLibrary()) +#pragma warning restore IDISP001 // Dispose created + if ((resolvedAssembly is not null) && resolvedAssembly.IsNetStandardLibrary()) { allTypes.AddRange(resolvedAssembly.MainModule.Types); } @@ -177,7 +177,9 @@ private IEnumerable GetNetStandardTypes() private IEnumerable GetTypesFromAssembly(string assemblyName) { +#pragma warning disable IDISP001 // Dispose created var assembly = _assemblyResolver.Resolve(assemblyName); +#pragma warning restore IDISP001 // Dispose created if (assembly is null) { return Array.Empty(); diff --git a/src/Catel.Fody/Core/ObservableObjectPropertyWeaver.cs b/src/Catel.Fody/Core/ObservableObjectPropertyWeaver.cs index a610e430..b13aaae8 100644 --- a/src/Catel.Fody/Core/ObservableObjectPropertyWeaver.cs +++ b/src/Catel.Fody/Core/ObservableObjectPropertyWeaver.cs @@ -113,7 +113,7 @@ private void UpdateSetValueCall(PropertyDefinition property) // IL_0008: call instance void Catel.Fody.TestAssembly.ObservableObjectTest_Expected/*0200004A*/::OnFirstNameChanged()/*060001C0*/ var changeCallbackReference = _propertyData.ChangeCallbackReference; - if (changeCallbackReference != null) + if (changeCallbackReference is not null) { newInstructions.Add(Instruction.Create(OpCodes.Ldarg_0)); newInstructions.Add(Instruction.Create(OpCodes.Call, changeCallbackReference)); diff --git a/src/Catel.Fody/Core/PropertyWeaverBase.cs b/src/Catel.Fody/Core/PropertyWeaverBase.cs index 3dbbaea1..7b453380 100644 --- a/src/Catel.Fody/Core/PropertyWeaverBase.cs +++ b/src/Catel.Fody/Core/PropertyWeaverBase.cs @@ -72,13 +72,13 @@ protected bool HasBackingField(PropertyDefinition property) var fieldName = GetBackingFieldName(property); var field = GetFieldReference(property.DeclaringType, fieldName, false); - return (field != null); + return (field is not null); } protected static FieldDefinition GetFieldDefinition(TypeDefinition declaringType, string fieldName, bool allowGenericResolving) { var fieldReference = GetFieldReference(declaringType, fieldName, allowGenericResolving); - return fieldReference != null ? fieldReference.Resolve() : null; + return fieldReference is not null ? fieldReference.Resolve() : null; } protected static FieldReference GetFieldReference(TypeDefinition declaringType, string fieldName, bool allowGenericResolving) diff --git a/src/Catel.Fody/Core/ReferenceCleaner.cs b/src/Catel.Fody/Core/ReferenceCleaner.cs index 1e9c5ca2..9fd3fea2 100644 --- a/src/Catel.Fody/Core/ReferenceCleaner.cs +++ b/src/Catel.Fody/Core/ReferenceCleaner.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System.Linq; @@ -19,7 +13,7 @@ public ReferenceCleaner(ModuleWeaver moduleWeaver) public void Execute() { var catelFodyAttributesReference = _moduleWeaver.ModuleDefinition.AssemblyReferences.FirstOrDefault(x => string.Equals(x.Name, "Catel.Fody.Attributes")); - if (catelFodyAttributesReference != null) + if (catelFodyAttributesReference is not null) { _moduleWeaver.WriteInfo("\tRemoving reference to 'Catel.Fody.Attributes', it is no longer required."); _moduleWeaver.ModuleDefinition.AssemblyReferences.Remove(catelFodyAttributesReference); diff --git a/src/Catel.Fody/Core/WeavingException.cs b/src/Catel.Fody/Core/WeavingException.cs index ede49f5f..1828e450 100644 --- a/src/Catel.Fody/Core/WeavingException.cs +++ b/src/Catel.Fody/Core/WeavingException.cs @@ -1,9 +1,3 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - namespace Catel.Fody { using System; diff --git a/src/Catel.Fody/Extensions/CecilCatelExtensions.cs b/src/Catel.Fody/Extensions/CecilCatelExtensions.cs index defdf674..c72fc9b4 100644 --- a/src/Catel.Fody/Extensions/CecilCatelExtensions.cs +++ b/src/Catel.Fody/Extensions/CecilCatelExtensions.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.Generic; using Mono.Cecil; diff --git a/src/Catel.Fody/Extensions/CecilExtensions.assembly.cs b/src/Catel.Fody/Extensions/CecilExtensions.assembly.cs index c41ba675..40fc3818 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.assembly.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.assembly.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; using Mono.Cecil; diff --git a/src/Catel.Fody/Extensions/CecilExtensions.attributes.cs b/src/Catel.Fody/Extensions/CecilExtensions.attributes.cs index 69f15fcd..ddeb7543 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.attributes.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.attributes.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.Generic; using System.Linq; @@ -68,7 +61,7 @@ public static bool IsDecoratedWithAttribute(this MethodDefinition methodDefiniti public static bool IsDecoratedWithAttribute(Collection customAttributes, string attributeName) { - return GetAttribute(customAttributes, attributeName) != null; + return GetAttribute(customAttributes, attributeName) is not null; } public static void RemoveAttribute(this TypeDefinition typeDefinition, string attributeName) diff --git a/src/Catel.Fody/Extensions/CecilExtensions.cs b/src/Catel.Fody/Extensions/CecilExtensions.cs index ce9c1a75..e5be8dc8 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; @@ -29,7 +23,9 @@ public static void FixPrivateCorLibScope(this TypeReference type) if (SystemRuntimeRef is null) { +#pragma warning disable IDISP001 // Dispose created var systemRuntimeAssembly = type.Module.ResolveAssembly("System.Runtime"); +#pragma warning restore IDISP001 // Dispose created SystemRuntimeRef = new AssemblyNameReference(systemRuntimeAssembly.Name.Name, systemRuntimeAssembly.GetVersion()) { @@ -98,7 +94,7 @@ public static TypeReference Import(this TypeReference typeReference, bool checkF if (checkForNullableValueTypes) { var nullableValueType = typeReference.GetNullableValueType(); - if (nullableValueType != null) + if (nullableValueType is not null) { return module.ImportReference(nullableValueType); } @@ -185,7 +181,7 @@ public static TypeReference GetNullableValueType(this TypeReference typeReferenc public static bool IsNullableValueType(this TypeReference typeReference) { - return GetNullableValueType(typeReference) != null; + return GetNullableValueType(typeReference) is not null; } public static MethodReference MakeHostInstanceGeneric(this MethodReference self, params TypeReference[] arguments) @@ -231,7 +227,9 @@ public static TypeDefinition FindType(this ModuleDefinition moduleDefinition, st return CachedTypeDefinitions[cacheKey]; } +#pragma warning disable IDISP001 // Dispose created var resolvedAssembly = moduleDefinition.ResolveAssembly(assemblyName); +#pragma warning restore IDISP001 // Dispose created if (resolvedAssembly is null) { return null; @@ -251,7 +249,7 @@ public static TypeDefinition FindType(this ModuleDefinition moduleDefinition, st select typeDefinition).FirstOrDefault(); } - if (type != null) + if (type is not null) { CachedTypeDefinitions[cacheKey] = type; return type; @@ -274,13 +272,13 @@ public static PropertyReference GetProperty(this TypeReference typeReference, st public static PropertyReference GetProperty(this TypeDefinition typeDefinition, string propertyName) { var type = typeDefinition; - while (type != null && !type.FullName.Contains("System.Object")) + while (type is not null && !type.FullName.Contains("System.Object")) { var propertyDefinition = (from property in type.Properties where string.Equals(propertyName, property.Name) select property).FirstOrDefault(); - if (propertyDefinition != null) + if (propertyDefinition is not null) { return propertyDefinition; } @@ -307,15 +305,17 @@ public static MethodReference GetMethod(this ModuleDefinition module, string met var resolver = module.AssemblyResolver; foreach (var assemblyReference in module.AssemblyReferences) { +#pragma warning disable IDISP001 // Dispose created var assembly = resolver.Resolve(assemblyReference.Name); - if (assembly != null) +#pragma warning restore IDISP001 // Dispose created + if (assembly is not null) { foreach (var type in assembly.MainModule.GetAllTypeDefinitions()) { var methodReference = (from method in type.Methods where method.Name == methodName select method).FirstOrDefault(); - if (methodReference != null) + if (methodReference is not null) { return methodReference; } @@ -455,7 +455,7 @@ public static IEnumerable GetBaseTypes(this TypeDefinition type, var interfaces = BuildInterfaces(current, previousGenericArgsMap); result.AddRange(interfaces); } - } while (current.BaseType != null); + } while (current.BaseType is not null); return result; } diff --git a/src/Catel.Fody/Extensions/CecilExtensions.debuginfo.cs b/src/Catel.Fody/Extensions/CecilExtensions.debuginfo.cs index 18d98d6b..f0ca630b 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.debuginfo.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.debuginfo.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2017 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Linq; using System.Reflection; diff --git a/src/Catel.Fody/Extensions/CecilExtensions.fields.cs b/src/Catel.Fody/Extensions/CecilExtensions.fields.cs index 1828317a..884bd82f 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.fields.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.fields.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using Mono.Cecil; diff --git a/src/Catel.Fody/Extensions/CecilExtensions.members.cs b/src/Catel.Fody/Extensions/CecilExtensions.members.cs index f77c8022..718e8050 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.members.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.members.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Linq; using Mono.Cecil; @@ -99,13 +92,13 @@ private static void MarkAsGeneratedCodeInternal(object obj, MsCoreReferenceFinde private static void MarkAsGeneratedCodeInternal(this Collection customAttributes, MsCoreReferenceFinder msCoreReferenceFinder, ModuleDefinition importingModule) { var generatedCodeAttribute = CreateGeneratedCodeAttribute(msCoreReferenceFinder, importingModule); - if (generatedCodeAttribute != null) + if (generatedCodeAttribute is not null) { customAttributes.Add(generatedCodeAttribute); } var debuggerAttribute = CreateDebuggerNonUserCodeAttribute(msCoreReferenceFinder, importingModule); - if (debuggerAttribute != null) + if (debuggerAttribute is not null) { customAttributes.Add(debuggerAttribute); } diff --git a/src/Catel.Fody/Extensions/CecilExtensions.methods.cs b/src/Catel.Fody/Extensions/CecilExtensions.methods.cs index 1732c465..d71115aa 100644 --- a/src/Catel.Fody/Extensions/CecilExtensions.methods.cs +++ b/src/Catel.Fody/Extensions/CecilExtensions.methods.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.Generic; using System.Linq; @@ -36,7 +29,7 @@ public static int FindBaseConstructorIndex(this MethodDefinition method) { var declaringType = method.DeclaringType; var baseType = declaringType?.BaseType; - if (baseType != null) + if (baseType is not null) { var instructions = method.Body.Instructions; @@ -107,12 +100,31 @@ public static MethodReference GetMethodReference(this MethodDefinition methodDef var definition = typeDefinitions.Pop(); // Only call lower class if possible - var containsMethod = (from method in definition.Methods - where method.Name == methodDefinition.Name - select method).Any(); - if (containsMethod) + var containingMethods = (from method in definition.Methods + where method.Name == methodDefinition.Name && + method.Parameters.Count == methodDefinition.Parameters.Count + select method).ToList(); + + foreach (var containingMethod in containingMethods) { - methodReference = methodReference.MakeGeneric(definition.BaseType); + // GH-361 fix: check parameters + var isValid = true; + + for (int i = 0; i < methodReference.Parameters.Count; i++) + { + var methodDefinitionParameter = methodReference.Parameters[i]; + var potentialMethodParameter = containingMethod.Parameters[i]; + if (methodDefinitionParameter.ParameterType.FullName != potentialMethodParameter.ParameterType.FullName) + { + isValid = false; + break; + } + } + + if (isValid) + { + methodReference = methodReference.MakeGeneric(definition.BaseType); + } } } diff --git a/src/Catel.Fody/Extensions/InstructionExtensions.cs b/src/Catel.Fody/Extensions/InstructionExtensions.cs index aafbbd16..2ceecd35 100644 --- a/src/Catel.Fody/Extensions/InstructionExtensions.cs +++ b/src/Catel.Fody/Extensions/InstructionExtensions.cs @@ -1,9 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- -namespace Catel.Fody +namespace Catel.Fody { using Mono.Cecil; using Mono.Cecil.Cil; diff --git a/src/Catel.Fody/Extensions/InstructionListExtensions.cs b/src/Catel.Fody/Extensions/InstructionListExtensions.cs index 1799c7d6..9b8e9aa0 100644 --- a/src/Catel.Fody/Extensions/InstructionListExtensions.cs +++ b/src/Catel.Fody/Extensions/InstructionListExtensions.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections.Generic; using System.Linq; diff --git a/src/Catel.Fody/Extensions/ResolvingExtensions.cs b/src/Catel.Fody/Extensions/ResolvingExtensions.cs index 4c2b110a..f3b3424a 100644 --- a/src/Catel.Fody/Extensions/ResolvingExtensions.cs +++ b/src/Catel.Fody/Extensions/ResolvingExtensions.cs @@ -1,9 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; diff --git a/src/Catel.Fody/Extensions/TypeReferenceExtensions.cs b/src/Catel.Fody/Extensions/TypeReferenceExtensions.cs index 4ee4d22b..8e00a3a5 100644 --- a/src/Catel.Fody/Extensions/TypeReferenceExtensions.cs +++ b/src/Catel.Fody/Extensions/TypeReferenceExtensions.cs @@ -38,7 +38,7 @@ public static IEnumerable Traverse(this TypeDefinition typeDefin // Base class var baseType = typeDefinition.BaseType; - if (baseType != null) + if (baseType is not null) { baseTypes.Add(baseType.Resolve()); } @@ -67,7 +67,7 @@ public static List GetHierarchy(this TypeDefinition typeD { hierarchy.Add(new TypeWithSelfReference(definition, null)); - if (breakCondition != null && breakCondition(definition)) + if (breakCondition is not null && breakCondition(definition)) { break; } @@ -124,7 +124,7 @@ public static bool IsAssignableFrom(this TypeReference target, TypeReference typ var checkedInterfaces = new HashSet(); var typeDefinition = type.Resolve(); - while (typeDefinition != null) + while (typeDefinition is not null) { if (typeDefinition.Equals(target)) { diff --git a/src/Catel.Fody/Extensions/XmlExtensions.cs b/src/Catel.Fody/Extensions/XmlExtensions.cs index 779f2e3a..844cfa5b 100644 --- a/src/Catel.Fody/Extensions/XmlExtensions.cs +++ b/src/Catel.Fody/Extensions/XmlExtensions.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Xml.Linq; @@ -15,7 +8,7 @@ public static class XmlExtensions public static void ReadBool(this XElement config, string nodeName, Action setter) { var attribute = config.Attribute(nodeName); - if (attribute != null) + if (attribute is not null) { if (bool.TryParse(attribute.Value, out var value)) { @@ -32,7 +25,7 @@ public static void ReadEnum(this XElement config, string nodeName, Action where TEnum : struct { var attribute = config.Attribute(nodeName); - if (attribute != null) + if (attribute is not null) { if (Enum.TryParse(attribute.Value, out var value)) { diff --git a/src/Catel.Fody/FodyEnvironment.cs b/src/Catel.Fody/FodyEnvironment.cs index 3a3b7a7d..9df0c900 100644 --- a/src/Catel.Fody/FodyEnvironment.cs +++ b/src/Catel.Fody/FodyEnvironment.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Xml.Linq; diff --git a/src/Catel.Fody/Helpers/CacheHelper.cs b/src/Catel.Fody/Helpers/CacheHelper.cs index ceec8192..02189d09 100644 --- a/src/Catel.Fody/Helpers/CacheHelper.cs +++ b/src/Catel.Fody/Helpers/CacheHelper.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody +namespace Catel.Fody { using System.Collections; using System.Collections.Generic; diff --git a/src/Catel.Fody/ModuleWeaver.cs b/src/Catel.Fody/ModuleWeaver.cs index adbe3e9c..918abc8a 100644 --- a/src/Catel.Fody/ModuleWeaver.cs +++ b/src/Catel.Fody/ModuleWeaver.cs @@ -1,9 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- -namespace Catel.Fody +namespace Catel.Fody { using System; using System.Collections.Generic; @@ -20,16 +15,16 @@ public ModuleWeaver() { } - public IAssemblyResolver AssemblyResolver { get; set; } - public override bool ShouldCleanReference => true; public override IEnumerable GetAssembliesForScanning() { - var assemblies = new List(); + var assemblies = new List + { + "netstandard" + }; // For now just return all references - assemblies.Add("netstandard"); assemblies.AddRange(ModuleDefinition.AssemblyReferences.Select(x => x.Name)); return assemblies; @@ -86,7 +81,9 @@ public override void Execute() WriteInfo("Running against Catel itself, most features will be disabled"); } +#pragma warning disable IDISP001 // Dispose created var catelCoreReference = AssemblyResolver.Resolve("Catel.Core"); +#pragma warning restore IDISP001 // Dispose created if (!configuration.IsRunningAgainstCatel && catelCoreReference is null) { WriteWarning("No reference to Catel.Core found, this weaver is useless without referencing Catel"); @@ -94,7 +91,7 @@ public override void Execute() } // Note: nested types not supported because we only list actual types (thus not nested) - var types = ModuleDefinition.GetTypes().Where(x => x.IsClass && x.BaseType != null).ToList(); + var types = ModuleDefinition.GetTypes().Where(x => x.IsClass && x.BaseType is not null).ToList(); var typeNodeBuilder = new CatelTypeNodeBuilder(types, msCoreReferenceFinder); typeNodeBuilder.Execute(); @@ -206,7 +203,7 @@ private void InitializeEnvironment() try { - FodyEnvironment.IsCatelCoreAvailable = assemblyResolver.Resolve("Catel.Core") != null; + FodyEnvironment.IsCatelCoreAvailable = assemblyResolver.Resolve("Catel.Core") is not null; } catch (Exception) { @@ -215,7 +212,7 @@ private void InitializeEnvironment() try { - FodyEnvironment.IsCatelMvvmAvailable = assemblyResolver.Resolve("Catel.MVVM") != null; + FodyEnvironment.IsCatelMvvmAvailable = assemblyResolver.Resolve("Catel.MVVM") is not null; } catch (Exception) { diff --git a/src/Catel.Fody/Services/ArgumentWeaverService.cs b/src/Catel.Fody/Services/ArgumentWeaverService.cs index b0386f9b..42c7b237 100644 --- a/src/Catel.Fody/Services/ArgumentWeaverService.cs +++ b/src/Catel.Fody/Services/ArgumentWeaverService.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Services +namespace Catel.Fody.Services { using System; using System.Collections.Generic; diff --git a/src/Catel.Fody/Services/AutoPropertiesWeaverService.cs b/src/Catel.Fody/Services/AutoPropertiesWeaverService.cs index 5cf4b268..0823251d 100644 --- a/src/Catel.Fody/Services/AutoPropertiesWeaverService.cs +++ b/src/Catel.Fody/Services/AutoPropertiesWeaverService.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Services +namespace Catel.Fody.Services { using Weaving.AutoProperties; diff --git a/src/Catel.Fody/Services/ExposedPropertiesWeaverService.cs b/src/Catel.Fody/Services/ExposedPropertiesWeaverService.cs index 92b5bfaa..f3c1099e 100644 --- a/src/Catel.Fody/Services/ExposedPropertiesWeaverService.cs +++ b/src/Catel.Fody/Services/ExposedPropertiesWeaverService.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Services +namespace Catel.Fody.Services { using Catel.Fody.Weaving.ExposedProperties; diff --git a/src/Catel.Fody/Services/LoggingWeaverService.cs b/src/Catel.Fody/Services/LoggingWeaverService.cs index aa22010f..8822f282 100644 --- a/src/Catel.Fody/Services/LoggingWeaverService.cs +++ b/src/Catel.Fody/Services/LoggingWeaverService.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Services +namespace Catel.Fody.Services { using System; using System.Collections.Generic; diff --git a/src/Catel.Fody/Services/XmlSchemasWeaverService.cs b/src/Catel.Fody/Services/XmlSchemasWeaverService.cs index de769bda..0d9bf50a 100644 --- a/src/Catel.Fody/Services/XmlSchemasWeaverService.cs +++ b/src/Catel.Fody/Services/XmlSchemasWeaverService.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Services +namespace Catel.Fody.Services { using System; @@ -67,12 +61,12 @@ private bool CatelVersionSupportsXmlSchemaManager(CatelType catelType) } var xmlSchemaManager = (TypeDefinition)catelType.TypeDefinition.Module.FindType("Catel.Core", "Catel.Runtime.Serialization.Xml.XmlSchemaManager"); - _isSupported = xmlSchemaManager != null; + _isSupported = xmlSchemaManager is not null; if (!_isSupported ?? false) { var xmlSchemaManagerPre38 = (TypeDefinition)catelType.TypeDefinition.Module.FindType("Catel.Core", "Catel.Runtime.Serialization.XmlSchemaManager"); - _isSupported = xmlSchemaManagerPre38 != null; + _isSupported = xmlSchemaManagerPre38 is not null; } } diff --git a/src/Catel.Fody/Weaving/Argument/ArgumentInstructionSequenceBuilder.cs b/src/Catel.Fody/Weaving/Argument/ArgumentInstructionSequenceBuilder.cs index 1dc2f53f..494139a5 100644 --- a/src/Catel.Fody/Weaving/Argument/ArgumentInstructionSequenceBuilder.cs +++ b/src/Catel.Fody/Weaving/Argument/ArgumentInstructionSequenceBuilder.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; using System.Text.RegularExpressions; @@ -70,7 +64,7 @@ private static IEnumerable BuildDefaultInstructionsInternal(object } var parameterDefinition = parameterDefinitionOrFieldDefinition as ParameterDefinition; - if (parameterDefinitionOrFieldDefinition != null) + if (parameterDefinitionOrFieldDefinition is not null) { return BuildDefaultInstructions(parameterDefinition); } diff --git a/src/Catel.Fody/Weaving/Argument/ArgumentMethodCallWeaverBase.cs b/src/Catel.Fody/Weaving/Argument/ArgumentMethodCallWeaverBase.cs index 7855f316..b9737e28 100644 --- a/src/Catel.Fody/Weaving/Argument/ArgumentMethodCallWeaverBase.cs +++ b/src/Catel.Fody/Weaving/Argument/ArgumentMethodCallWeaverBase.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System; using System.Collections.Generic; @@ -28,18 +22,18 @@ public bool Execute(TypeDefinition type, MethodDefinition methodDefinition, MethodDefinition selectedMethod = null; var parameterDefinition = parameterDefinitionOrFieldDefinition as ParameterDefinition; - if (parameterDefinition != null) + if (parameterDefinition is not null) { targetType = parameterDefinition.ParameterType; } var fieldDefinition = parameterDefinitionOrFieldDefinition as FieldDefinition; - if (fieldDefinition != null) + if (fieldDefinition is not null) { targetType = fieldDefinition.FieldType; } - if (targetType != null) + if (targetType is not null) { try { @@ -50,7 +44,7 @@ public bool Execute(TypeDefinition type, MethodDefinition methodDefinition, var error = $"[{type.FullName}.{methodDefinition.Name}] {ex.Message}"; var sequencePoint = methodDefinition.GetFirstSequencePoint(); - if (sequencePoint != null) + if (sequencePoint is not null) { FodyEnvironment.WriteErrorPoint(error, sequencePoint); } @@ -73,12 +67,12 @@ public bool Execute(TypeDefinition type, MethodDefinition methodDefinition, var instructions = new List(); - if (parameterDefinition != null) + if (parameterDefinition is not null) { BuildInstructions(moduleDefinition, type, methodDefinition, parameterDefinition, attribute, instructions); } - if (fieldDefinition != null) + if (fieldDefinition is not null) { BuildInstructions(moduleDefinition, type, methodDefinition, fieldDefinition, attribute, instructions); } diff --git a/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.cs b/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.cs index c94b3a6b..e06659f3 100644 --- a/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; using Mono.Cecil; @@ -14,21 +8,16 @@ namespace Catel.Fody.Weaving.Argument public partial class ArgumentWeaver { - #region Constants private delegate CustomAttribute ExpressionToAttributeFunc(MethodReference method, IList instructions, Instruction instruction); private static readonly object CacheLock = new object(); - #endregion - #region Fields private static readonly Dictionary ExpressionChecksToAttributeMappings = new Dictionary(); private readonly TypeDefinition _typeDefinition; private readonly MsCoreReferenceFinder _msCoreReferenceFinder; private readonly Configuration _configuration; - #endregion - #region Constructors public ArgumentWeaver(TypeDefinition typeDefinition, MsCoreReferenceFinder msCoreReferenceFinder, Configuration configuration) { @@ -38,12 +27,10 @@ public ArgumentWeaver(TypeDefinition typeDefinition, MsCoreReferenceFinder msCor _msCoreReferenceFinder = msCoreReferenceFinder; _configuration = configuration; } - #endregion - #region Methods public void Execute() { - FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{_typeDefinition.FullName}'"); + //FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{_typeDefinition.FullName}'"); foreach (var method in _typeDefinition.Methods) { @@ -69,7 +56,7 @@ private void ProcessMethod(MethodDefinition method) Collection instructions = null; var methodFullName = method.GetFullName(); - FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{methodFullName}'"); + //FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{methodFullName}'"); // Step 1) Convert attributes // TODO: how to handle async/await here? @@ -102,7 +89,7 @@ private void ProcessMethod(MethodDefinition method) var displayClasses = new List(); // Go backwards to keep the order of the arguments correct (because argument checks are injected at the beginning of the ctor) - if (instructions != null || ContainsArgumentChecks(method)) + if (instructions is not null || ContainsArgumentChecks(method)) { if (instructions is null) { @@ -180,7 +167,7 @@ private void ProcessMethod(MethodDefinition method) //} } - if (instructions != null) + if (instructions is not null) { method.Body.OptimizeMacros(); method.UpdateDebugInfo(); @@ -319,6 +306,5 @@ private bool IsOperandSupportedForArgumentChecks(object operand) return true; } - #endregion } } diff --git a/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.expressions.cs b/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.expressions.cs index 8ad72fe4..daedc10c 100644 --- a/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.expressions.cs +++ b/src/Catel.Fody/Weaving/Argument/ArgumentWeaver.expressions.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; using System.Linq; @@ -194,7 +187,7 @@ private void RemoveObsoleteCodeForArgumentExpression(MethodDefinition method, Co // Search var fieldOfDisplayClass = method.DeclaringType.Fields.FirstOrDefault(x => x.FieldType.Name.Equals(displayClassType.Name)); - if (fieldOfDisplayClass != null) + if (fieldOfDisplayClass is not null) { // Async in DEBUG mode for (var j = i + 1; j < instructions.Count - 1; j++) @@ -281,7 +274,7 @@ private void RemoveObsoleteCodeForArgumentExpression(MethodDefinition method, Co var startIndex = i; var endIndex = i; - if (fieldOfDisplayClass != null && instruction.UsesField(fieldOfDisplayClass)) + if (fieldOfDisplayClass is not null && instruction.UsesField(fieldOfDisplayClass)) { // Option A endIndex = i; @@ -547,7 +540,7 @@ private RemoveArgumentWeavingCallResult RemoveArgumentWeavingCall(MethodDefiniti { // First call to ldtoken with FieldDefinition contains the display class type var fieldDefinition = GetFieldDefinition(innerInstruction); - if (fieldDefinition != null) + if (fieldDefinition is not null) { displayClassType = fieldDefinition.DeclaringType; } @@ -626,7 +619,7 @@ private object GetParameterOrFieldForExpressionArgumentCheck(MethodDefinition me { // First call to ldtoken with FieldDefinition contains the display class type parameterFieldDefinition = GetFieldDefinition(innerInstruction); - if (parameterFieldDefinition != null) + if (parameterFieldDefinition is not null) { displayClassType = parameterFieldDefinition.DeclaringType; } diff --git a/src/Catel.Fody/Weaving/Argument/BoundariesCheckRelatedArgumentMethodCallWeaverBase.cs b/src/Catel.Fody/Weaving/Argument/BoundariesCheckRelatedArgumentMethodCallWeaverBase.cs index 46c5fc0a..31b7e285 100644 --- a/src/Catel.Fody/Weaving/Argument/BoundariesCheckRelatedArgumentMethodCallWeaverBase.cs +++ b/src/Catel.Fody/Weaving/Argument/BoundariesCheckRelatedArgumentMethodCallWeaverBase.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; diff --git a/src/Catel.Fody/Weaving/Argument/DefaultArgumentMethodCallWeaverBase.cs b/src/Catel.Fody/Weaving/Argument/DefaultArgumentMethodCallWeaverBase.cs index 973fc3b8..9220ec99 100644 --- a/src/Catel.Fody/Weaving/Argument/DefaultArgumentMethodCallWeaverBase.cs +++ b/src/Catel.Fody/Weaving/Argument/DefaultArgumentMethodCallWeaverBase.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/ImplementsInterfaceArgumentMethodCallWeave.cs b/src/Catel.Fody/Weaving/Argument/Implementations/ImplementsInterfaceArgumentMethodCallWeave.cs index 3e3ff2ee..e9486adc 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/ImplementsInterfaceArgumentMethodCallWeave.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/ImplementsInterfaceArgumentMethodCallWeave.cs @@ -1,9 +1,3 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsMatchArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsMatchArgumentMethodCallWeaver.cs index 83d281ba..ba2d73cd 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsMatchArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsMatchArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsMaximumMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsMaximumMethodCallWeaver.cs index 32c3a722..99269f09 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsMaximumMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsMaximumMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsMinimalMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsMinimalMethodCallWeaver.cs index 745ae4e5..78ef3e8f 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsMinimalMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsMinimalMethodCallWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; using Mono.Cecil; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotMatchArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotMatchArgumentMethodCallWeaver.cs index 07163d4c..596afa34 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotMatchArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotMatchArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullArgumentMethodCallWeaver.cs index 661c1ce8..2af9e813 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System; using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArgumentMethodCallWeaver.cs index 923a70e3..2ef185b9 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArrayArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArrayArgumentMethodCallWeaver.cs index 4cddb0ce..6b5b39f6 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArrayArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrEmptyArrayArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrWhitespaceArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrWhitespaceArgumentMethodCallWeaver.cs index 95f60a31..9694670e 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrWhitespaceArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotNullOrWhitespaceArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotOutOfRangeMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotOutOfRangeMethodCallWeaver.cs index f694f779..dec7512a 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsNotOutOfRangeMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsNotOutOfRangeMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Implementations/IsOfTypeArgumentMethodCallWeave.cs b/src/Catel.Fody/Weaving/Argument/Implementations/IsOfTypeArgumentMethodCallWeave.cs index f013a897..288a78fa 100644 --- a/src/Catel.Fody/Weaving/Argument/Implementations/IsOfTypeArgumentMethodCallWeave.cs +++ b/src/Catel.Fody/Weaving/Argument/Implementations/IsOfTypeArgumentMethodCallWeave.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/InheritsFromArgumentMethodCallWeaver.cs b/src/Catel.Fody/Weaving/Argument/InheritsFromArgumentMethodCallWeaver.cs index 7a5a2e06..efd2cb02 100644 --- a/src/Catel.Fody/Weaving/Argument/InheritsFromArgumentMethodCallWeaver.cs +++ b/src/Catel.Fody/Weaving/Argument/InheritsFromArgumentMethodCallWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Linq; diff --git a/src/Catel.Fody/Weaving/Argument/Models/RemoveArgumentWeavingCallResult.cs b/src/Catel.Fody/Weaving/Argument/Models/RemoveArgumentWeavingCallResult.cs index ce01f04c..5eb1ec5d 100644 --- a/src/Catel.Fody/Weaving/Argument/Models/RemoveArgumentWeavingCallResult.cs +++ b/src/Catel.Fody/Weaving/Argument/Models/RemoveArgumentWeavingCallResult.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2016 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.Argument.Models +namespace Catel.Fody.Weaving.Argument.Models { using Mono.Cecil; diff --git a/src/Catel.Fody/Weaving/Argument/RegexRelatedArgumentMethodCallWeaverBase.cs b/src/Catel.Fody/Weaving/Argument/RegexRelatedArgumentMethodCallWeaverBase.cs index 65ac511e..17f03f65 100644 --- a/src/Catel.Fody/Weaving/Argument/RegexRelatedArgumentMethodCallWeaverBase.cs +++ b/src/Catel.Fody/Weaving/Argument/RegexRelatedArgumentMethodCallWeaverBase.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.Argument +namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; diff --git a/src/Catel.Fody/Weaving/Argument/TypeCheckRelatedArgumentMethodCallWeaverBase.cs b/src/Catel.Fody/Weaving/Argument/TypeCheckRelatedArgumentMethodCallWeaverBase.cs index e772ed26..9474920e 100644 --- a/src/Catel.Fody/Weaving/Argument/TypeCheckRelatedArgumentMethodCallWeaverBase.cs +++ b/src/Catel.Fody/Weaving/Argument/TypeCheckRelatedArgumentMethodCallWeaverBase.cs @@ -1,9 +1,3 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - namespace Catel.Fody.Weaving.Argument { using System.Collections.Generic; diff --git a/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWarningChecker.cs b/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWarningChecker.cs index 453a6023..32387606 100644 --- a/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWarningChecker.cs +++ b/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWarningChecker.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.AutoProperties +namespace Catel.Fody.Weaving.AutoProperties { using System.Collections.Generic; using System.Linq; @@ -25,7 +19,7 @@ private void Process(List catelTypes) foreach (var propertyData in catelType.Properties.ToList()) { var warning = CheckForWarning(propertyData); - if (warning != null) + if (warning is not null) { FodyEnvironment.WriteDebug($"\t{propertyData.PropertyDefinition.GetName()} {warning} property will be ignored."); catelType.Properties.Remove(propertyData); @@ -39,6 +33,12 @@ public string CheckForWarning(CatelTypeProperty propertyData) var propertyDefinition = propertyData.PropertyDefinition; var setMethod = propertyDefinition.SetMethod; + if (setMethod is null) + { + // Init-only property, will be migrated to full property + return null; + } + if (setMethod.Name == "set_Item" && setMethod.Parameters.Count == 2 && setMethod.Parameters[1].Name == "value") { return "Property is an indexer."; diff --git a/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWeaver.cs b/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWeaver.cs index 5941cebc..82376742 100644 --- a/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWeaver.cs +++ b/src/Catel.Fody/Weaving/AutoProperties/AutoPropertiesWeaver.cs @@ -1,12 +1,7 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.AutoProperties +namespace Catel.Fody.Weaving.AutoProperties { using System.Collections.Generic; + using Mono.Cecil; using Mono.Cecil.Rocks; public class AutoPropertiesWeaver @@ -38,7 +33,33 @@ private void Process(List catelTypes) foreach (var propertyData in catelType.Properties) { - var body = propertyData.PropertyDefinition.SetMethod.Body; + var setMethod = propertyData.PropertyDefinition.SetMethod; + if (setMethod is null) + { + //[CompilerGenerated] + //set_PropertyName + //{ + + // k__BackingField = value; + //} + + // Generate set method + setMethod = new Mono.Cecil.MethodDefinition($"set_{propertyData.Name}", Mono.Cecil.MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName, + catelType.TypeDefinition.Module.ImportReference(_msCoreReferenceFinder.GetCoreTypeReference("Void"))); + + // Add first before doing anything else + catelType.TypeDefinition.Methods.Add(setMethod); + propertyData.PropertyDefinition.SetMethod = setMethod; + + setMethod.Parameters.Add(new ParameterDefinition(catelType.TypeDefinition.Module.ImportReference(propertyData.PropertyDefinition.PropertyType)) + { + Name = "value" + }); + + setMethod.MarkAsCompilerGenerated(_msCoreReferenceFinder); + } + + var body = setMethod.Body; body.SimplifyMacros(); diff --git a/src/Catel.Fody/Weaving/AutoProperties/OnPropertyChangedWeaver.cs b/src/Catel.Fody/Weaving/AutoProperties/OnPropertyChangedWeaver.cs index dbe2f0c0..18356ea2 100644 --- a/src/Catel.Fody/Weaving/AutoProperties/OnPropertyChangedWeaver.cs +++ b/src/Catel.Fody/Weaving/AutoProperties/OnPropertyChangedWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.AutoProperties +namespace Catel.Fody.Weaving.AutoProperties { using System.Linq; using Mono.Cecil; @@ -14,21 +7,16 @@ namespace Catel.Fody.Weaving.AutoProperties internal class OnPropertyChangedWeaver { - #region Fields private readonly CatelType _catelType; private readonly MsCoreReferenceFinder _msCoreReferenceFinder; - #endregion - - #region Constructors + public OnPropertyChangedWeaver(CatelType catelType, MsCoreReferenceFinder msCoreReferenceFinder) { _catelType = catelType; _msCoreReferenceFinder = msCoreReferenceFinder; } - #endregion - #region Methods public void Execute() { FodyEnvironment.WriteDebug($"\tExecuting '{GetType().Name}' for '{_catelType.TypeDefinition.FullName}'"); @@ -195,6 +183,5 @@ private MethodDefinition EnsureOnPropertyChangedMethod() return methodDefinition; } - #endregion } } diff --git a/src/Catel.Fody/Weaving/AutoProperties/RaisePropertyChangedWeaver.cs b/src/Catel.Fody/Weaving/AutoProperties/RaisePropertyChangedWeaver.cs index c52a7db4..6fa3e3c5 100644 --- a/src/Catel.Fody/Weaving/AutoProperties/RaisePropertyChangedWeaver.cs +++ b/src/Catel.Fody/Weaving/AutoProperties/RaisePropertyChangedWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.AutoProperties +namespace Catel.Fody.Weaving.AutoProperties { using System.Collections.Generic; using System.Data; @@ -104,7 +97,7 @@ private void FixRaisePropertyChangedMethod(MethodDefinition method) if (potentialInstruction.IsOpCode(OpCodes.Ldtoken)) { var methodDefinition = potentialInstruction.Operand as MethodDefinition; - if (methodDefinition != null) + if (methodDefinition is not null) { var name = methodDefinition.Name; if (name.StartsWith("get_")) diff --git a/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWarningChecker.cs b/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWarningChecker.cs index 8614842b..2e55bdc0 100644 --- a/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWarningChecker.cs +++ b/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWarningChecker.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.ExposedProperties +namespace Catel.Fody.Weaving.ExposedProperties { using System.Collections.Generic; diff --git a/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWeaver.cs b/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWeaver.cs index 71944304..a5541763 100644 --- a/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWeaver.cs +++ b/src/Catel.Fody/Weaving/ExposedProperties/ExposedPropertiesWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.ExposedProperties +namespace Catel.Fody.Weaving.ExposedProperties { using System.Linq; using Mono.Cecil; @@ -77,7 +70,7 @@ private void ProcessProperty(CatelType catelType, CatelTypeProperty modelPropert where string.Equals(property.Name, "IsReadOnly") select property).FirstOrDefault(); - if (isReadOnlyProperty.Argument.Value != null) + if (isReadOnlyProperty.Argument.Value is not null) { isReadOnly = (bool)isReadOnlyProperty.Argument.Value; } diff --git a/src/Catel.Fody/Weaving/Logging/LoggingWeaver.cs b/src/Catel.Fody/Weaving/Logging/LoggingWeaver.cs index 6bf17cea..aabbb2bf 100644 --- a/src/Catel.Fody/Weaving/Logging/LoggingWeaver.cs +++ b/src/Catel.Fody/Weaving/Logging/LoggingWeaver.cs @@ -1,11 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2014 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - - -namespace Catel.Fody.Weaving.Logging +namespace Catel.Fody.Weaving.Logging { using System; using System.Linq; @@ -93,7 +86,7 @@ private void UpdateCallsToGetCurrentClassLogger(MethodBody ctorBody) var message = $"Cannot change method call for log '{type.FullName}', the GetLogger(type) method does not exist on the calling type (try to use LogManager.GetCurrentClassLogger())"; - if (point != null) + if (point is not null) { FodyEnvironment.WriteWarningPoint(message, point); } diff --git a/src/Catel.Fody/Weaving/XmlSchemas/XmlSchemasWeaver.cs b/src/Catel.Fody/Weaving/XmlSchemas/XmlSchemasWeaver.cs index 18469193..66630359 100644 --- a/src/Catel.Fody/Weaving/XmlSchemas/XmlSchemasWeaver.cs +++ b/src/Catel.Fody/Weaving/XmlSchemas/XmlSchemasWeaver.cs @@ -1,10 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) 2008 - 2013 Catel development team. All rights reserved. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace Catel.Fody.Weaving.XmlSchemas +namespace Catel.Fody.Weaving.XmlSchemas { using System.Linq; using Mono.Cecil; @@ -65,7 +59,7 @@ private bool AddXmlSchemaProviderAttribute(CatelType catelType) var existingCustomAttribute = (from attribute in catelTypeDefinition.CustomAttributes where string.Equals(attribute.AttributeType.Name, "XmlSchemaProviderAttribute") select attribute).FirstOrDefault(); - if (existingCustomAttribute != null) + if (existingCustomAttribute is not null) { var constructorArgument = existingCustomAttribute.ConstructorArguments[0]; if (string.Equals(constructorArgument.Value, methodName)) diff --git a/src/Directory.Build.analyzers.props b/src/Directory.Build.analyzers.props index 94942db1..90e3fd32 100644 --- a/src/Directory.Build.analyzers.props +++ b/src/Directory.Build.analyzers.props @@ -4,21 +4,18 @@ --> - - build; native; contentfiles; analyzers - - - build; native; contentfiles; analyzers - - - - build; native; contentfiles; analyzers - - + + + + + + + latest + + $(ProjectDir)..\..\output\$(Configuration) + + + <__OverridableOutputPathDefault>$(OverridableOutputRootPath)\$(MSBuildProjectName)\ $(OverridableOutputRootPath)\$(MSBuildProjectName)\ - $(OverridableOutputPath) + $(OverridableOutputRootPath)\$(OutputTargetAssemblyDirectory)\ + + + + $(OverridableOutputPath)\..\$(MSBuildProjectName)\ + $(OverridableOutputPath) bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml @@ -95,13 +121,17 @@ - + + false + + + @@ -152,11 +182,47 @@ - + $(DefineConstants);NETCORE;NETCORE5;NETCORE5_0;NET5;NET5_0 - + + + + + + + + + + $(DefineConstants);NETCORE;NETCORE6;NETCORE6_0;NET6;NET6_0 + + + + + + + + + + + + $(DefineConstants);NETCORE;NETCORE7;NETCORE7_0;NET7;NET7_0 + + + + + + + + + + + + $(DefineConstants);NETCORE;NETCORE8;NETCORE8_0;NET8;NET8_0 + + + @@ -311,7 +377,7 @@ - <_InstallerTargetFramework>net451 + <_InstallerTargetFramework>net48 diff --git a/src/Directory.Build.shared.implicit.props b/src/Directory.Build.shared.implicit.props index 33d45dc6..9a0ce4cd 100644 --- a/src/Directory.Build.shared.implicit.props +++ b/src/Directory.Build.shared.implicit.props @@ -41,10 +41,17 @@ true - + + full true + + + + portable + true + diff --git a/src/Directory.Build.shared.mat.props b/src/Directory.Build.shared.mat.props index f2b30f0b..67fee25f 100644 --- a/src/Directory.Build.shared.mat.props +++ b/src/Directory.Build.shared.mat.props @@ -10,6 +10,7 @@ en-US true true + true @@ -18,10 +19,12 @@ + + - + diff --git a/src/Directory.Build.shared.tools.props b/src/Directory.Build.shared.tools.props index 6e996dd8..67c48b0c 100644 --- a/src/Directory.Build.shared.tools.props +++ b/src/Directory.Build.shared.tools.props @@ -6,31 +6,35 @@ --> - $(TargetsForTfmSpecificBuildOutput);GetToolsPackageFiles $(Description) $(PackageProjectUrl) + IncludeDefaultProjectBuildOutputInPack - - + + - - - - - + + + - - $([MSBuild]::MakeRelative('$(OutputPath)', %(ToolDllFiles.FullPath))) - + - - $([MSBuild]::MakeRelative('$(OutputPath)', %(ToolExeFiles.FullPath))) - + + + + $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolDllFiles.FullPath))) + tools + + + + $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolExeFiles.FullPath))) + tools + - \ No newline at end of file diff --git a/src/Directory.Build.shared.xamltools.props b/src/Directory.Build.shared.xamltools.props new file mode 100644 index 00000000..ae3196ba --- /dev/null +++ b/src/Directory.Build.shared.xamltools.props @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + false + + + + true + + + + + False + False + False + + + + + True + + + + + False + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/global.json b/src/global.json index 4bd12a9c..02e177d6 100644 --- a/src/global.json +++ b/src/global.json @@ -1,9 +1,9 @@ { "msbuild-sdks": { - "MSBuild.Sdk.Extras": "3.0.23" + "MSBuild.Sdk.Extras": "3.0.44" }, "sdk": { - "version": "5.0.0", + "version": "6.0.0", "rollForward": "latestMinor", "allowPrerelease": false } diff --git a/src/nuget.config b/src/nuget.config index 975d0b66..d7dd5aa9 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -1,6 +1,20 @@  - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + diff --git a/tools/nuget.exe b/tools/nuget.exe index ea492dbc..97bf83bd 100644 Binary files a/tools/nuget.exe and b/tools/nuget.exe differ diff --git a/tools/packages.config b/tools/packages.config index 194a7e12..29e63e03 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,5 +1,4 @@ - - +