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

Ported Fake.Sql.DacPac to FAKE 5 #1878

Merged
merged 2 commits into from
Apr 22, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 15 additions & 0 deletions Fake.sln
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Api.HockeyApp", "src/a
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.JavaScript.Yarn", "src/app/Fake.JavaScript.Yarn/Fake.JavaScript.Yarn.fsproj", "{DE7579F2-C20F-4C35-BC04-C10362912243}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Fake.Sql.DacPac", "src/app/Fake.Sql.DacPac/Fake.Sql.DacPac.fsproj", "{3BC4A91C-3381-4BF9-BF11-8E06706CF878}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -722,6 +724,18 @@ Global
{DE7579F2-C20F-4C35-BC04-C10362912243}.Release|x64.Build.0 = Release|Any CPU
{DE7579F2-C20F-4C35-BC04-C10362912243}.Release|x86.ActiveCfg = Release|Any CPU
{DE7579F2-C20F-4C35-BC04-C10362912243}.Release|x86.Build.0 = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|x64.ActiveCfg = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|x64.Build.0 = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|x86.ActiveCfg = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Debug|x86.Build.0 = Debug|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|Any CPU.Build.0 = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|x64.ActiveCfg = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|x64.Build.0 = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|x86.ActiveCfg = Release|Any CPU
{3BC4A91C-3381-4BF9-BF11-8E06706CF878}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -779,6 +793,7 @@ Global
{819E2756-7BEE-4FCD-BA08-7BF323405CBE} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
{B636A082-4DB4-439D-8A37-E5214BDC00A3} = {901F162F-8925-4390-89C5-9EE2C343F744}
{DE7579F2-C20F-4C35-BC04-C10362912243} = {901F162F-8925-4390-89C5-9EE2C343F744}
{3BC4A91C-3381-4BF9-BF11-8E06706CF878} = {7BFFAE76-DEE9-417A-A79B-6A6644C4553A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {058A0C5E-2216-4306-8AFB-0AE28320C26A}
Expand Down
1 change: 1 addition & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ let dotnetAssemblyInfos =
"Fake.Windows.Chocolatey", "Running and packaging with Chocolatey"
"Fake.Testing.SonarQube", "Analyzing your project with SonarQube"
"Fake.DotNet.Testing.OpenCover", "Code coverage with OpenCover"
"Fake.Sql.DacPac", "Sql Server Data Tools DacPac operations"
"Fake.Documentation.DocFx", "Documentation with DocFx" ]

let assemblyInfos =
Expand Down
29 changes: 29 additions & 0 deletions help/markdown/dacpac.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Packaging and Deploying SQL Databases

FAKE can be used to create a SQL DACPAC and also deploy it to a SQL Server using the MSDeploy executable. This is installed by default with Visual Studio and with the SQL Server Data Tools (SSDT) package.

DACPACs automatically diff from the source to the destination and generate the SQL script dynamically.

You can read up more on DACPac and MSDeploy arguments [here](https://msdn.microsoft.com/en-us/library/hh550081%28v=vs.103%29.aspx).

## Sample usage

Ensure that you have already built your database project (you can do this with standard MSBuild). Then, use the ``deployDb`` command to deploy the ``dbProject.dacpac`` to the ``myDatabase``.

open Fake.Sql

/// the database for local development + compile
Target.create "DeployLocalDb" (fun _ ->
let connectionString = "Data Source=(localdb)\MSSQLLocalDB;Integrated Security=True;Database=MyDatabase;Pooling=False"
let dacPacPath = "path/to/dbProject.dacpac"
DacPac.deployDb (fun args -> { args with Source = dacPacPath; Destination = localDbConnectionString }) |> ignore)

## Deployment Options

You can optionally specify the type of command to use (again, refer to the documentation above for more detail): -

* Deploy - full deploy to destination
* Script - SQL script
* Report - XML report of diff

In addition, you can also elect to deploy to Dacpac files rather than SQL databases - simply pass in the pass to the dacpac that you wish to generate.
14 changes: 7 additions & 7 deletions help/markdown/help-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ For example topics about "Targets" like "specifictargets" has been added to the
You can find a link to the old documentation at the top of the new documentation.

So to find the old documentation you usually:

* Find the module in the navigation
* Navigate to the FAKE 4 docs (linked at the top in bold)

> NOTE: This page might be removed without further notice once FAKE 5 has been released!

Here is the old sidebar:

## FAKE - F# Make

* [Old Startpage](legacy-index.html)

## Get FAKE via NuGet

* [Source Code on GitHub](https://github.com/fsharp/FAKE)
Expand All @@ -29,7 +30,7 @@ Here is the old sidebar:

* [Getting started](gettingstarted.html)
* [Build script caching](cache.html)

* [NuGet package restore](nuget.html)
* [Using FxCop in a build](fxcop.html)
* [Generating AssemblyInfo](assemblyinfo.html)
Expand All @@ -55,9 +56,8 @@ Here is the old sidebar:
* [Using Slack](slacknotification.html)
* [Using Microsoft Teams](msteamsnotification.html)
* [Using SonarQube](sonarcube.html)

* [Fake.Deploy](deploy.html)
* [Fake.IIS](iis.html)

* [API Reference](apidocs/index.html)

* [API Reference](apidocs/index.html)
2 changes: 1 addition & 1 deletion help/redirects/dacpac.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

This page moved to:

- Not yet migrated to FAKE 5
- [here for FAKE 5](dac-pack.html)
- [here for FAKE 4](todo-dacpac.html) (Final location not decided yet)
17 changes: 17 additions & 0 deletions src/app/Fake.Sql.DacPac/AssemblyInfo.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Auto-Generated by FAKE; do not edit
namespace System
open System.Reflection

[<assembly: AssemblyTitleAttribute("FAKE - F# Make Sql Server Data Tools DacPac operations")>]
[<assembly: AssemblyProductAttribute("FAKE - F# Make")>]
[<assembly: AssemblyVersionAttribute("5.0.0")>]
[<assembly: AssemblyInformationalVersionAttribute("5.0.0-rc005")>]
[<assembly: AssemblyFileVersionAttribute("5.0.0")>]
do ()

module internal AssemblyVersionInformation =
let [<Literal>] AssemblyTitle = "FAKE - F# Make Sql Server Data Tools DacPac operations"
let [<Literal>] AssemblyProduct = "FAKE - F# Make"
let [<Literal>] AssemblyVersion = "5.0.0"
let [<Literal>] AssemblyInformationalVersion = "5.0.0-rc005"
let [<Literal>] AssemblyFileVersion = "5.0.0"
25 changes: 25 additions & 0 deletions src/app/Fake.Sql.DacPac/Fake.Sql.DacPac.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworks>net46;netstandard1.6;netstandard2.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);DOTNETCORE</DefineConstants>
<AssemblyName>Fake.Sql.DacPac</AssemblyName>
<OutputType>Library</OutputType>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="Sql.DacPac.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Fake.Core.Environment\Fake.Core.Environment.fsproj" />
<ProjectReference Include="..\Fake.Core.Process\Fake.Core.Process.fsproj" />
<ProjectReference Include="..\Fake.IO.FileSystem\Fake.IO.FileSystem.fsproj" />
</ItemGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);NETSTANDARD2_0</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
</PropertyGroup>
<Import Project="..\..\..\.paket\Paket.Restore.targets" />
</Project>
118 changes: 118 additions & 0 deletions src/app/Fake.Sql.DacPac/Sql.DacPac.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
namespace Fake.Sql

/// Contains helpers around deploying databases.
[<RequireQualifiedAccess>]
module DacPac =

open Fake.Core
open Fake.IO.FileSystemOperators
open Fake.IO.Globbing.Operators
open System.IO
open System

/// The type of action to execute.
type DeployAction =
/// Generate and apply a synchronisation script between two databases.
| Deploy
/// Generate a SQL script to sync two databases.
| Script of OutputPath:string
/// Generate an XML report for the differences between two databases.
| Report of OutputPath:string

/// Configuration arguments for DacPac deploy
type DeployDbArgs = {
/// The path to SqlPackage.exe.
SqlPackageToolPath : string
/// Type of action to execute. Defaults to Deploy.
Action : DeployAction
/// Path to source (path to DACPAC or Connection String).
Source : string
/// Path to destination (path to DACPAC or Connection String).
Destination : string
/// Timeout for deploy (defaults to 120 seconds).
Timeout : int
/// Block deployment if data loss can occur. Defaults to true.
BlockOnPossibleDataLoss : bool
/// Drops objects in the destination that do not exist in the source. Defaults to false.
DropObjectsNotInSource : bool
/// Recreates the database from scratch on publish (rather than an in-place update). Defaults to false.
RecreateDb : bool
/// Additional configuration parameters required by sqlpackage.exe
AdditionalSqlPackageProperties : (string * string) list
/// SQLCMD variables
Variables : (string * string) list }

let validPaths =
let getSqlVersion (path:string) = path.Split '\\' |> Array.item 3 |> int
let getVsVersion path = (Path.GetDirectoryName path |> DirectoryInfo).Name |> int
let sql = !!(Environment.ProgramFilesX86 </> @"Microsoft SQL Server\**\DAC\bin\SqlPackage.exe") |> Seq.map(fun path -> path, getSqlVersion path)
let vs = !!(Environment.ProgramFilesX86 </> @"Microsoft Visual Studio*\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\*\SqlPackage.exe") |> Seq.map(fun path -> path, getVsVersion path)

[ sql; vs ]
|> List.collect Seq.toList
|> List.sortByDescending snd
|> List.map fst

/// The default DacPac deployment arguments.
let DefaultDeploymentArgs =
{ SqlPackageToolPath =
validPaths
|> List.tryHead
|> defaultArg <| ""
Action = Deploy
Source = ""
Destination = ""
Timeout = 120
BlockOnPossibleDataLoss = true
DropObjectsNotInSource = false
RecreateDb = false
AdditionalSqlPackageProperties = []
Variables = [] }

module PropertyKeys =
/// When creating a new SQL Azure database, specifies the database service tier to use e.g. S2, P1
let sqlAzureDbSize = "DatabaseServiceObjective"

let private generateCommandLine args =
let action, outputPath =
match args with
| Deploy -> "Publish", None
| Script outputPath -> "Script", Some outputPath
| Report outputPath -> "DeployReport", Some outputPath
let outputPath = defaultArg(outputPath |> Option.map(sprintf """/OutputPath:"%s" """)) ""
action, outputPath

/// Deploys a SQL DacPac or database to another database or DacPac.
let deployDb setParams =
let args = setParams DefaultDeploymentArgs
let action, outputPath = generateCommandLine args.Action

let concat parameter =
List.map (fun (key, value) -> sprintf "/%s:%s=%s" parameter key value)
>> String.concat " "

let additionalParameters = args.AdditionalSqlPackageProperties |> concat "p"

let variables = args.Variables |> concat "v"

if System.String.IsNullOrWhiteSpace args.SqlPackageToolPath then
failwith "No SqlPackage.exe filename was given."

if not (File.Exists args.SqlPackageToolPath) then
let paths =
if validPaths |> List.contains args.SqlPackageToolPath then validPaths
else [ args.SqlPackageToolPath ]
failwithf "Unable to find a valid instance of SqlPackage.exe. Paths checked were: %A." paths

let result =
Process.execRaw
(fun psi -> { psi with Arguments = sprintf """/Action:%s /SourceFile:"%s" /TargetConnectionString:"%s" %s /p:BlockOnPossibleDataLoss=%b /p:DropObjectsNotInSource=%b /p:CommandTimeout=%d /p:CreateNewDatabase=%b %s %s""" action args.Source args.Destination outputPath args.BlockOnPossibleDataLoss args.DropObjectsNotInSource args.Timeout args.RecreateDb additionalParameters variables; FileName = args.SqlPackageToolPath })
TimeSpan.MaxValue
true
(printfn "SqlPackage error: %s")
(printfn "%s")

match result with
| 0 -> ()
| _ -> failwith "Error executing DACPAC deployment. Please see output for error details."

4 changes: 4 additions & 0 deletions src/app/Fake.Sql.DacPac/paket.references
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
group netcore

FSharp.Core
NETStandard.Library
6 changes: 6 additions & 0 deletions src/legacy/FakeLib/Sql.DacPac.fs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// Contains helpers around deploying databases.
[<System.Obsolete("Please open Fake.Sql instead and use the Fake.Sql.DacPac module (FAKE0001 - package: Fake.Sql.DacPac, module: DacPac)")>]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a small problem. Because now you cannot actually fix that warning according to the migration guide (because old and new namespace are the same and we cannot include the new module into fakelib, because of naming conflict).

So we either remove this file and add only the new module (and have a breaking change because of RequireQualifiedAccess) or find a different solution

module Fake.Sql.DacPac

open Fake.EnvironmentHelper
Expand All @@ -9,6 +10,7 @@ open System.Diagnostics
open System

/// The type of action to execute.
[<System.Obsolete("FAKE0001 Use `open Fake.Sql` and `DacPac.DeployAction`")>]
type DeployAction =
/// Generate and apply a synchronisation script between two databases.
| Deploy
Expand All @@ -18,6 +20,7 @@ type DeployAction =
| Report of OutputPath:string

/// Configuration arguments for DacPac deploy
[<System.Obsolete("FAKE0001 Use `open Fake.Sql` and `DacPac.DeployDbArgs`")>]
type DeployDbArgs = {
/// The path to SqlPackage.exe.
SqlPackageToolPath : string
Expand All @@ -40,6 +43,7 @@ type DeployDbArgs = {
/// SQLCMD variables
Variables : (string * string) list }

[<System.Obsolete("FAKE0001 Use `open Fake.Sql` and `DacPac.validPaths`")>]
let validPaths =
let getSqlVersion (path:string) = path.Split '\\' |> Array.item 3 |> int
let getVsVersion path = (Path.GetDirectoryName path |> DirectoryInfo).Name |> int
Expand All @@ -52,6 +56,7 @@ let validPaths =
|> List.map fst

/// The default DacPac deployment arguments.
[<System.Obsolete("FAKE0001 Use `open Fake.Sql` and `DacPac.DefaultDeploymentArgs`")>]
let defaultDeploymentArgs =
{ SqlPackageToolPath =
validPaths
Expand Down Expand Up @@ -81,6 +86,7 @@ let private generateCommandLine args =
action, outputPath

/// Deploys a SQL DacPac or database to another database or DacPac.
[<System.Obsolete("FAKE0001 Use `open Fake.Sql` and `DacPac.deployDb`")>]
let deployDb setParams =
let args = setParams defaultDeploymentArgs
let action, outputPath = generateCommandLine args.Action
Expand Down