Skip to content

Commit

Permalink
Add support for dotnet publish (#487)
Browse files Browse the repository at this point in the history
* Add support for dotnet publish

* Fix test

* Add condition to target override

* Set property directly instead of importing BeforeCommon.targets
  • Loading branch information
zijchen authored Sep 25, 2024
1 parent 510d2e3 commit 2c6e18d
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 36 deletions.
1 change: 1 addition & 0 deletions src/Microsoft.Build.Sql/sdk/Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<TargetFramework Condition="'$(TargetFramework)' == '' AND '$(NetCoreBuild)' == 'true'">netstandard2.1</TargetFramework>
<!-- Allow packages of all target frameworks to be referenced by the sqlproj -->
<PackageTargetFallback Condition="'$(PackageTargetFallback)' == ''">@(SupportedTargetFramework->'%(Alias)')</PackageTargetFallback>
<PublishDirName Condition="'$(PublishDirName)' == ''">publish</PublishDirName>
</PropertyGroup>

<!-- building in Visual Studio requires some sort of TargetFrameworkVersion. So we condition to NetCoreBuild as false to avoid failures -->
Expand Down
16 changes: 15 additions & 1 deletion src/Microsoft.Build.Sql/sdk/Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
<NoWarn>$(NoWarn),NU5128</NoWarn>
</PropertyGroup>

<!-- Publish target properties -->
<PropertyGroup>
<PublishDirName Condition="'$(PublishDirName)' == ''">publish</PublishDirName>
<PublishDir Condition="'$(PublishDir)' == ''">$(OutputPath)$(PublishDirName)\</PublishDir>
</PropertyGroup>

<Target Name="CreateManifestResourceNames" />
<!-- CoreCompile is a target inside target Build on Microsoft.Common.targets that is not implemented there but allows us to personalize our compile/build flow, while
executing all the other targets inside Build regularly. We implement it before importing Common.targets because it's not implemented there, so it will not be
Expand All @@ -48,21 +54,29 @@
<Import Condition="'$(NetCoreBuild)' == 'true'" Project="$(MSBuildThisFileDirectory)../tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets"/>
<Import Condition="'$(NetCoreBuild)' != 'true' AND '$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
<Import Condition="'$(NetCoreBuild)' != 'true' AND '$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />

<Import Condition="'$(NetCoreBuild)' == 'true'" Project="$(MSBuildSdksPath)/Microsoft.NET.Sdk/targets/Microsoft.NET.DefaultAssemblyInfo.targets" />
<Import Condition="'$(NetCoreBuild)' == 'true'" Project="$(MSBuildSdksPath)/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.targets" />
<Import Condition="'$(NetCoreBuild)' == 'true'" Project="$(MSBuildSdksPath)/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets" />

<Import Condition="'$(NetCoreBuild)' != 'true' AND Exists('$(MSBuildExtensionsPath)\Sdks\Microsoft.SqlProject.Sdk\ssdtprojectsystem.targets')"
Project="$(MSBuildExtensionsPath)\Sdks\Microsoft.SqlProject.Sdk\ssdtprojectsystem.targets" />

<UsingTask TaskName="AllowEmptyTelemetry" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />

<!-- Add dacpac file BuiltProjectOutputGroupOutput, so that it will get included in the NuGet package by the Pack target -->
<Target Name="AddDacpacToBuiltProjectOutputGroupOutput" BeforeTargets="BuiltProjectOutputGroup">
<ItemGroup>
<BuiltProjectOutputGroupOutput Include="$(SqlTargetPath)" TargetPath="$(SqlTargetFile)" FinalOutputPath="$(SqlTargetPath)" />
</ItemGroup>
</Target>

<Target Name="AddDacpacToPublishList" BeforeTargets="ComputeResolvedFilesToPublishList">
<ItemGroup>
<ResolvedFileToPublish Include="$(SqlTargetPath)" RelativePath="$(SqlTargetFile)" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
</Target>

<ItemGroup>
<!-- This is necessary for building on non-Windows platforms. -->
<PackageReference Condition="'$(NetCoreBuild)' == 'true'" Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" IsImplicitlyDefined="true" />
Expand Down
47 changes: 41 additions & 6 deletions test/Microsoft.Build.Sql.Tests/DotnetTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.Build.Construction;
using Microsoft.SqlServer.Dac;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
Expand Down Expand Up @@ -36,10 +37,19 @@ protected string CurrentTestDataDirectory
get { return Path.Combine(this.CommonTestDataDirectory, TestUtils.EscapeTestName(TestContext.CurrentContext.Test.Name)); }
}

private string LocalNugetSource
{
get { return Path.Combine(this.WorkingDirectory, "pkg"); }
}

[SetUp]
public void TestSetup()
{
EnvironmentSetup();

// Add pkg folder as a nuget source
RunGenericDotnetCommand($"nuget add source \"{LocalNugetSource}\" --name TestSource_{TestContext.CurrentContext.Test.Name}", out _, out string stdError);
Assert.AreEqual("", stdError, "Failed to add local nuget source: " + stdError);
}

[TearDown]
Expand Down Expand Up @@ -85,8 +95,7 @@ protected void EnvironmentSetup()
}

// Copy SDK nuget package to Workingdirectory/pkg/
string localNugetSource = Path.Combine(this.WorkingDirectory, "pkg");
TestUtils.CopyDirectoryRecursive("../../../pkg", localNugetSource);
TestUtils.CopyDirectoryRecursive("../../../pkg", LocalNugetSource);

// Copy common project files from Template to WorkingDirectory
TestUtils.CopyDirectoryRecursive("../../../Template", this.WorkingDirectory);
Expand All @@ -96,10 +105,6 @@ protected void EnvironmentSetup()
{
TestUtils.CopyDirectoryRecursive(this.CurrentTestDataDirectory, this.WorkingDirectory);
}

// Add pkg folder as a nuget source
RunGenericDotnetCommand($"nuget add source \"{localNugetSource}\" --name TestSource_{TestContext.CurrentContext.Test.Name}", out _, out string stdError);
Assert.AreEqual("", stdError, "Failed to add local nuget source: " + stdError);
}

/// <summary>
Expand Down Expand Up @@ -294,6 +299,36 @@ protected void AddProjectReference(params string[] projects)
ProjectUtils.AddItemGroup(this.GetProjectFilePath(), "ProjectReference", projects);
}

/// <summary>
/// Add a package reference to a Nuget package.
/// </summary>
protected void AddPackageReference(string packageName, string version, string serverSqlcmdVariable = "", string databaseSqlcmdVariable = "", string databaseVariableLiteralValue = "", bool? suppressMissingDependenciesErrors = null)
{
ProjectUtils.AddItemGroup(this.GetProjectFilePath(), "PackageReference", new string[] { packageName }, (ProjectItemElement item) => {
item.AddMetadata("Version", version);

if (!string.IsNullOrEmpty(serverSqlcmdVariable))
{
item.AddMetadata("ServerSqlCmdVariable", serverSqlcmdVariable);
}

if (!string.IsNullOrEmpty(databaseSqlcmdVariable))
{
item.AddMetadata("DatabaseSqlCmdVariable", databaseSqlcmdVariable);
}

if (!string.IsNullOrEmpty(databaseVariableLiteralValue))
{
item.AddMetadata("DatabaseVariableLiteralValue", databaseVariableLiteralValue);
}

if (suppressMissingDependenciesErrors.HasValue)
{
item.AddMetadata("SuppressMissingDependenciesErrors", suppressMissingDependenciesErrors.ToString());
}
});
}

/// <summary>
/// Returns the full path to the sqlproj file used for this test.
/// </summary>
Expand Down
29 changes: 0 additions & 29 deletions test/Microsoft.Build.Sql.Tests/PackageReferenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Construction;
using NUnit.Framework;

namespace Microsoft.Build.Sql.Tests
Expand Down Expand Up @@ -110,33 +109,5 @@ public void VerifyPackageReferenceToMasterAndGenerateCreateScript()
this.VerifyDacPackage();
FileAssert.Exists(Path.Combine(this.GetOutputDirectory(), $"{DatabaseProjectName}_Create.sql"));
}

private void AddPackageReference(string packageName, string version, string serverSqlcmdVariable = "", string databaseSqlcmdVariable = "", string databaseVariableLiteralValue = "", bool? suppressMissingDependenciesErrors = null)
{
// Add a package reference to ReferenceProj version 5.5.5
ProjectUtils.AddItemGroup(this.GetProjectFilePath(), "PackageReference", new string[] { packageName }, (ProjectItemElement item) => {
item.AddMetadata("Version", version);

if (!string.IsNullOrEmpty(serverSqlcmdVariable))
{
item.AddMetadata("ServerSqlCmdVariable", serverSqlcmdVariable);
}

if (!string.IsNullOrEmpty(databaseSqlcmdVariable))
{
item.AddMetadata("DatabaseSqlCmdVariable", databaseSqlcmdVariable);
}

if (!string.IsNullOrEmpty(databaseVariableLiteralValue))
{
item.AddMetadata("DatabaseVariableLiteralValue", databaseVariableLiteralValue);
}

if (suppressMissingDependenciesErrors.HasValue)
{
item.AddMetadata("SuppressMissingDependenciesErrors", suppressMissingDependenciesErrors.ToString());
}
});
}
}
}
104 changes: 104 additions & 0 deletions test/Microsoft.Build.Sql.Tests/PublishTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.IO;
using Microsoft.Build.Construction;
using NUnit.Framework;

namespace Microsoft.Build.Sql.Tests
{
[TestFixture]
public class PublishTests : DotnetTestBase
{
[Test]
public void VerifySimplePublish()
{
int exitCode = this.RunDotnetCommandOnProject("publish", out _, out string stdError);

// Verify success
Assert.AreEqual(0, exitCode, "Publish failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyDacPackage();
this.VerifyPublishFolder();
}

[Test]
public void VerifyPublishWithNoBuild()
{
// Run build first
int exitCode = this.RunDotnetCommandOnProject("publish", out _, out string stdError);
Assert.AreEqual(0, exitCode, "Build failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyDacPackage();

// Run publish with --no-build
exitCode = this.RunDotnetCommandOnProject("publish --no-build", out _, out stdError);
Assert.AreEqual(0, exitCode, "publish failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyPublishFolder();
}

[Test]
public void VerifyPublishkWithIncludedFiles()
{
// Add a content file that is copied to output
string includedContent = Path.Combine(this.WorkingDirectory, "include_content.txt");
File.WriteAllText(includedContent, "test");
ProjectUtils.AddItemGroup(this.GetProjectFilePath(), "Content", new[] { includedContent }, (ProjectItemElement item) =>
{
item.AddMetadata("CopyToOutputDirectory", "PreserveNewest");
});

// Run dotnet publish
int exitCode = this.RunDotnetCommandOnProject("publish", out _, out string stdError);

// Verify
Assert.AreEqual(0, exitCode, "Publish failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyPublishFolder("include_content.txt");
}

[Test]
public void VerifyPublishWithProjectReference()
{
// Add a project reference to ReferenceProj, which should be copied to the publish directory
string tempFolder = TestUtils.CreateTempDirectory();
TestUtils.CopyDirectoryRecursive(Path.Combine(this.CommonTestDataDirectory, "ReferenceProj"), tempFolder);

this.AddProjectReference(Path.Combine(tempFolder, "ReferenceProj.sqlproj"));

int exitCode = this.RunDotnetCommandOnProject("publish", out _, out string stdError);

Assert.AreEqual(0, exitCode, "Publish failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyDacPackage();
this.VerifyPublishFolder("ReferenceProj.dacpac");
}

[Test]
public void VerifyPublishWithPackageReference()
{
// Add a package reference to master.dacpac, which should be copied to the publish directory
this.AddPackageReference(packageName: "Microsoft.SqlServer.Dacpacs.Azure.Master", version: "160.*");

int exitCode = this.RunDotnetCommandOnProject("publish", out _, out string stdError);

Assert.AreEqual(0, exitCode, "Publish failed with error " + stdError);
Assert.AreEqual(string.Empty, stdError);
this.VerifyDacPackage();
this.VerifyPublishFolder("master.dacpac");
}

/// <summary>
/// Verify dacpac is in the publish directory, along with any additional expected files.
/// </summary>
private void VerifyPublishFolder(params string[] additionalFiles)
{
string publishFolder = Path.Combine(this.GetOutputDirectory(), "publish");
FileAssert.Exists(Path.Combine(publishFolder, $"{DatabaseProjectName}.dacpac"));
foreach (string file in additionalFiles) {
FileAssert.Exists(Path.Combine(publishFolder, file));
}
}
}
}

0 comments on commit 2c6e18d

Please sign in to comment.