Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for dotnet publish #487

Merged
merged 5 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -12,6 +12,7 @@
<NetCoreBuild Condition="'$(NetCoreBuild)' == '' And '$(MSBuildRuntimeType)' == 'Full'">false</NetCoreBuild>
<NETCoreTargetsPath Condition="$(NETCoreTargetsPath) == ''">$(MSBuildThisFileDirectory)..\tools\netstandard2.1</NETCoreTargetsPath>
<TargetFramework Condition="'$(TargetFramework)' == '' AND '$(NetCoreBuild)' == 'true'">netstandard2.1</TargetFramework>
<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));
}
}
}
}