MSBuild SqlPublishTask not running pre-deploy script? - msbuild

I have a SQL Server Database Project in Visual Studio 2015. This project is being used by the CI/CD tool to publish to the target databases using msbuild with a SqlPublishTask and an associated publish profile.
The msbuild command looks something like:
"C:\Program Files (x86)\MSBuild\14.0\Bin\msbuild.exe" "c:\pathto\MySqlProj\MySql.sqlproj" /t:Publish /p:SqlPublishProfilePath="c:\pathto\MySqlProj\MyProfile.publish.xml" /p:UpdateDatabase=True /p:PublishScriptFileName="MySqlProj.ssdt-artefact.sql" /m /nr:false
Any schema related changes are successfully published.
However, the pre-build sql script is not run. I can see this because old data that should be removed by the pre-build script is not. I have also tested the pre-build script separately and it works fine.
I have checked and the pre-build script has a Build Action of PreDeploy. The location of the pre-build script in the project is:
c:\pathto\MySqlProj\Scripts\Pre-Deploy\Script.PreDeployment.sql
Any idea why the pre-deploy script is not running?

Managed to solve this. From experimentation it looks like even though a pre-deployment script is created using the Pre-Deployment Script template this doesn't mark the file as being a pre-deployment script.
Instead, it appears that MSBuild is looking for a specific comment section at the start of the file in order to determine if it is a pre-deployment script:
/*
Pre-Deployment Script Template
--------------------------------------------------------------------------------------
This file contains SQL statements that will be executed before the build script.
Use SQLCMD syntax to include a file in the pre-deployment script.
Example: :r .\myfile.sql
Use SQLCMD syntax to reference a variable in the pre-deployment script.
Example: :setvar TableName MyTable
SELECT * FROM [$(TableName)]
--------------------------------------------------------------------------------------
*/
In my case, those comments had been removed. Adding them back resulted in the script being run. The same is true for post-deployment scripts.

Related

Run MSBuild from Command Line task in Azure Devops

I'm trying to execute msbuild on Azure Devops. Because of that I cannot use the MSBuild task provided.
When I use a Command Line task the command is not recognised. On my local machine I load vcvarsall.bat before I use msbuild. But I've not been unable to work out how to obtain that path in Azure Devops. Doesn't appear to be a Develop Command Prompt task for Azue Devops either.
Any ideas on how I can use msbuild from a Command Line task or Batch Script task? Using their Hosted VS agent.
The best way to do this in a supported way is to use vswhere. The following bit of script will install vswhere (using chocolatey) and then query the installer registry where msbuild can be found. Replace -latest with a more specific version if you need that:
choco install vswhere
for /f "tokens=*" %%i in ('vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe -nologo') do set msbuildpath="%%i"
echo "##vso[task.setvariable variable=msbuildpath]%msbuildpath%"
This will save the path to msbuild to the environment variable %msbuildpath% as well as the pipeline variable (for this stage) $(msbuildpath).
You can then either use a second run commandline task and pass in $(msbuildpath) or you can simply call MsBuild from the same piece of script mentioned above by calling:
%msbuildpath%
This will make sure your script will remain working, even if Microsoft upgrades their images and moves some things around (which does happen).
You can also get vswhere using wget or invoke-webrequest -outfile from the following location:
https://github.com/Microsoft/vswhere/releases/latest/download/vswhere.exe
Other samples for vswhere syntax can be found on the project wiki, including the syntax for PowerShell.
If you use Hosted Agent 2017 you can run the msbuild.exe from the Command Line task in this way:
Command Line version 1:
Command Line version 2:
Results:
If you are interested in seeing how the built-in Microsoft task resolves the path, all the Azure Devops tasks are provided open-source. These are the path functions you probably care to review.
Here is the solution I came up with using only built-in pipeline tasks which makes the MSBuild bin directory available on the path environment variable.
Create a PowerShell task to generate an MSBuild project to capture and output to a file the variables you are interested in (ex. MSBuildBinPath)
PowerShell script
"<Project DefaultTargets=`"DetectMsBuild`">
<ItemGroup>
<OutFile Include=`"`$(MsBuildDetectionFile)`" />
<OutFile Condition=`"'`$(OutFile)' == ''`" Include=`"msbuildInfo.json`" />
</ItemGroup>
<Target Name=`"DetectMsBuild`">
<PropertyGroup>
<MsBuildPaths>
[{
`"Name`": `"BinPath`",
`"Value`": `"`$(MSBuildBinPath.Replace('\', '\\'))`"
}]
</MsBuildPaths>
</PropertyGroup>
<WriteLinesToFile
File=`"#(Outfile)`"
Lines=`"`$(MsBuildPaths)`"
Overwrite=`"true`"
Encoding=`"UTF-8`" />
</Target>
</Project>" | Out-File -FilePath "msbuilddetect.proj" -Encoding utf8
Set the working directory and any variables accordingly.
PowerShell task settings screenshot:
Create an MSBuild task to run the project file generated by the previous task. Ensure the MSBuild version is set to the version you want to use.
MSBuild task settings screenshot:
Last, create another PowerShell task that will parse the outputted JSON file of the extracted variables and sets environment variables accordingly.
PowerShell script
Write-Host "Current path: $($env.Path)`n`n"
$msBuildVariables = Get-Content -Path msbuildInfo.json | ConvertFrom-Json
$Path = "$($msBuildVariables[0].Value);$($env:Path)"
Write-Host "##vso[task.setvariable variable=Path;]$Path"
PowerShell task settings screenshot:
Here is a screenshot of the task order in the build pipeline.

USQL msbuild - composite build output

I'm following the instructions on this link https://blogs.msdn.microsoft.com/azuredatalake/2017/10/24/continuous-integration-made-easy-with-msbuild-support-for-u-sql-preview/
It states that
After running MSBuild from command line or as a VSTS task, all scripts in the U-SQL project are built and output to a single file at "Build output path/script name/script name.usql". You can copy this composite U-SQL script to the release folder for further deployment.
Within my Visual Studio project (.usqlproj) I have multiple .usql scripts
CreateDatabase.usql
CreateTable.usql
CreateTvf.usql
when I do clean and msbuild and then check bin\debug folder, all I get is just CreateDatabase.usql and within that there is only CREATE DATBASE statement. As per the blog I would have thought all the 3 usql scripts would have merged into 1 composite usql script. The msbuild command I executed from command prompt on my machine
msbuild TheProject\TheProject.usqlproj /t:Clean /t:Rebuild /property:USQLSDKPath=C:\TheProject\src\packages\Microsoft.Azure.DataLake.USQL.SDK.1.3.1019-preview\build\runtime,USQLTargetType=Merge
I'm using Visual Studio 2017 15.4.3 and Azure Data Lake tools 2.3.0000.1
What am I doing wrong?
Due to some legacy reasons, to make sure all files in the usqlproj are built, the condition are defined in
USqlSDKBuild.targets as below
<ItemGroup>
<FileToBuild Condition="'$(JustOneFile)' == '' and
'$(Build_all_files_in_this_project)' != 'true'" Include="$(ActiveFile)" />
<FileToBuild Condition="'$(JustOneFile)' != '' " Include="$(JustOneFile)" />
<FileToBuild Condition="'$(Build_all_files_in_this_project)' == 'true'"
Include="Build_all_files_in_this_project" />
</ItemGroup>
For current preview release, please add "/property:Build_all_files_in_this_project=true,JustOneFile=''" to the command line to make sure all scripts are built. We will update this in later releases with a easier and simpler condition.
The command msbuild TheProject\TheProject.usqlproj /t:Clean /t:Rebuild /property:USQLSDKPath=C:\TheProject\src\packages\Microsoft.Azure.DataLake.USQL.SDK.1.3.1019-preview\build\runtime,USQLTargetType=Merge actually build the script you selected.
If you are selecting CreateDatabase.usql in VS, it will build the script CreateDatabase.usql in command line.
As below example, since it's selecting test.usql, when execute msbuild command, it will only build test.usql. As the way clicking Build button for the USQL project.
If you want to build all the scripts under the USQL project, you should select Build All Scripts button in VS.

Error running powershell task in TFS Build vnext

I have a very simple script which spits out environment variables like this:
Write-Host "SYSTEM_TEAMPROJECT: $ENV:SYSTEM_TEAMPROJECT"
My build has one step, the PowerShell task. The task script filename is set to the path to the script in TFSVC e.g. $/Main/BuildProcessTemplates/AllProps.ps1.
When I queue a new build it fails reporting the following error: "The term 'C:\Builds\agent_work\cb535ea3\Main' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again."
Have I configured the task incorrectly?
-- UPDATE: Here's a copy of the powershell task
Under the repository tab you need to include the script like below. If you have a directory of scripts you can select the folder instead.

What is the MSBuild 2010 script file equivalent of the command line switch /t:Package

I can see that MSBuild makes use of the /t:Package on the command line, but what's the euivalent for including this option in an msbuild script file.
The equivalent in a build script file is to use the MsBuild task. See link below.
Msdn Build Task
Are you invoking an msbuild script from another script using the MsBuild task? If so, the parameter you want to use is Targets http://msdn.microsoft.com/en-us/library/z7f65y0d.aspx.

execute sql script embedded in my setup project

I need to run a sql script while installing my program. I made a bat file which runs the script, and created a custom action on the commit of the setup project. The idea is the installer puts the file.sql(contained into my main project) in the installation path and then the custom action uses this file. How can this be possible?? Because doing this I get
this error: "There is a problem with this win installer package. A program run as part of the setup did not finish as expected.". Thanks.
You use SQLCMD to do this in your .bat file. A good example exists on TechRepublic. See figure B on how to configure your path. Another path example is shown in a brief article about a SQLCMD startup script; search for "startup script" on the page.