2

I have the following situation:

A SQL project in which i have a nuget package installed. This package (merely a PS script) is responsible for unpacking the DACPACs that the DB requires, using references to paths relative to the solution folder (to find the packages/ and dacpacs/ folders and to browse through the projects which it extracts from the .sln file). This is called as a pre-build event.

When building the entire solution, the $(SolutionDir) is defined, as expected (locally and ADO).

When building the test project, the $(SolutionDir) is either '' or '*Undefined*'. Again, as expected, because msbuild has no knowledge about the solution when building a single project. I can live with this caveat locally, no problem.

The question is this: is there something "magical" out there that i can use to make this work in Azure DevOps?

I can try various hacks, if anyone is aware of such methods, although i would like a clean solution.

Tried so far:

1) Adding the following PropertyGroup:

<PropertyGroup>
  <SolutionDir Condition="'$(SolutionDir)' == '' Or '$(SolutionDir)' == '*Undefined*'">.\</SolutionDir>
</PropertyGroup>

to the test project.

2) Following these sugestions: Prebuild event in Visual Studio replacing $(SolutionDir) with *Undefined*

No effect.

Silviu Preda
  • 628
  • 1
  • 10
  • 31
  • Feel free to let me know if it helps or not. If it doesn't work for your scenario, I guess maybe you have a different folder structure like mine. Share the details about your folder structure here and we can modify the script together to make it work for your folder structure also ~ – LoLance Apr 24 '20 at 09:42
  • Structure is something of this sort: D:\VSTSBuildAgents\\_work\791\s\ – Silviu Preda Apr 24 '20 at 10:11

1 Answers1

4

If your folder structure is something like:

1.The Azure Devops Repos contains the solution folder(where exists the xx.sln file).

2.And those projects are under same solution folder.

You can try my script:

  <PropertyGroup>
    <ProjectFolder>$([System.IO.Directory]::GetParent($(ProjectDir)))</ProjectFolder>
    <MySolutionDir>$([System.IO.Directory]::GetParent($(ProjectFolder)))\</MySolutionDir>
  </PropertyGroup>

The $(MySolutionDir) represents the path where your sln file and project folders exists. Same like $(SolutionDir), it also has the \. So it's format looks like SomePath\.

And it's recommended to insert my script above the script of PreBuild event. Something like:

  <PropertyGroup>
    <ProjectFolder>$([System.IO.Directory]::GetParent($(ProjectDir)))</ProjectFolder>
    <MySolutionDir>$([System.IO.Directory]::GetParent($(ProjectFolder)))\</MySolutionDir>
    It's recommended to add my script and PreBuildEvent in same propertyGroup, and mine should be in the first.
    <PreBuildEvent>echo $(MySolutionDir)</PreBuildEvent> 
  </PropertyGroup>

Edit1:

You can also add condition on that:

  <PropertyGroup>
    <ProjectFolder>$([System.IO.Directory]::GetParent($(ProjectDir)))</ProjectFolder>
    <MySolutionDir>$([System.IO.Directory]::GetParent($(ProjectFolder)))\</MySolutionDir>
    <SolutionDir Condition="xxxx">$(MySolutionDir)</SolutionDir>
    It's recommended to add my script and PreBuildEvent in same propertyGroup, and mine should be in the first.
    <PreBuildEvent>echo $(MySolutionDir)</PreBuildEvent> 
  </PropertyGroup>

Edit2:

Hmm, I now can reproduce the issue on my side. It's quite a strange behavior and I'm not sure about the root cause of this one. But a quick workaround is to create a new PropertyGroup to insert our custom script instead inserting it into existing PropertyGroup from default template:

It used to be:

  ....
  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
    <!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
    <SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
    <VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
    <ProjectFolder>$([System.IO.Directory]::GetParent($'(ProjectDir)'))</ProjectFolder>
    <ParentFolder>$([System.IO.Directory]::GetParent($'(ProjectFolder)'))\</ParentFolder>
    <SolutionDir Condition=" '$(SolutionDir)' == '' Or '$(SolutionDir)' == '*Undefined*' ">$(ParentFolder)</SolutionDir>
    <PreBuildEvent>echo $(SolutionDir)</PreBuildEvent>
  </PropertyGroup>
  <Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
  <Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
  <ItemGroup>
    <Folder Include="Properties" />
  </ItemGroup>
  <ItemGroup>
    <Build Include="test.sql" />
  </ItemGroup>
  <PropertyGroup>
    <PreBuildEvent>echo $(SolutionDir)</PreBuildEvent>
  </PropertyGroup>
</Project>

Now change it to be:

  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
    <!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
    <SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
    <VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
  </PropertyGroup>
  <Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
  <Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
  <ItemGroup>
    <Folder Include="Properties" />
  </ItemGroup>
  <ItemGroup>
    <Build Include="test.sql" />
  </ItemGroup>
  <PropertyGroup>
    <ProjectFolder>$([System.IO.Directory]::GetParent($(ProjectDir)))</ProjectFolder>
    <ParentFolder>$([System.IO.Directory]::GetParent($(ProjectFolder)))\</ParentFolder>
    <SolutionDir Condition=" '$(SolutionDir)' == '' Or '$(SolutionDir)' == '*Undefined*' ">$(ParentFolder)</SolutionDir>
    <PreBuildEvent>echo $(SolutionDir)</PreBuildEvent>
  </PropertyGroup>

Also, remove the extra ' in $(ProjectDir). It should be $(ProjectDir) instead of $'(ProjectDir)' and $'(ProjectFolder)'. I also see you have two PreBuildEvent properties, just keep the one in our custom script. After above steps, you project now works well on my side:

enter image description here

LoLance
  • 25,666
  • 1
  • 39
  • 73
  • 1
    Not really a solution, now Visual Studio complains that ProjectDir is '', rendering saving the project impossible. It's not the first time i have the ProjectDir issue, this has happened before, in some of my previous attempts. Especially the one with the build.props file – Silviu Preda Apr 24 '20 at 10:18
  • But your initial assumption about the folder structure is correct. Root contains .sln and the 2 folders, let's call them MyDatabase\ and MyDatabase.Tests\ – Silviu Preda Apr 24 '20 at 10:26
  • Update: I have tried placing single quotes around the ProjectDir, and now VS does not complain anymore. However, now, even when i build the solutions, the value gets evaluated to D:\VSTSAgents\\\_work\\_tasks\VSBuild_71a9a2d3-a98a-4caa-96ab-affca411ecda\1.166.0\... – Silviu Preda Apr 24 '20 at 12:24
  • Update 2: sorted the above issue by introducing the condition. However, i am now getting the following path when building single projects: 'D:\VSTSAgents\\\_work\3320\s\bin\Debug\', which is 2 levels 2 high. Almost feels like GetParent does nothing... – Silviu Preda Apr 24 '20 at 12:52
  • What's the content of your build.props file? I guess the issue about your ProjectDir is related to that file. If you have a clean solution with several projects in it, you may find my answer works well cause we have similar file structure. Try disabling that file and make the test again ... – LoLance Apr 27 '20 at 09:15
  • The file has been long removed, so that's not the cause of this issue. I have removed it even before reaching out to the SO community. – Silviu Preda Apr 27 '20 at 11:39
  • Sorry for the delay, but have you tried to do the test in a clean new solution and same project structure? I guess your issue could be related to your project files, structure or what. A minimal sample in github to help me reproduce that issue and check for you? – LoLance Apr 29 '20 at 10:01
  • Let me do exactly that, I'll get back with a link. Thanks for the involvement, this is driving me nuts :) – Silviu Preda Apr 29 '20 at 11:28
  • https://github.com/silviumihaipreda/SolutionDirSample here is a very short example – Silviu Preda Apr 30 '20 at 05:48
  • Great, I'll check it then and reply if I have any update later in this day. – LoLance Apr 30 '20 at 05:54
  • @SilviuPreda Your minimal sample is great for me to reproduce the issue, you can check my edit2 to get a quick workaround with little changes to resolve that strange behavior. (Hhh, I guess the reason why it always works on my side is because I like creating a new PropertyGroup to insert my custom script.) Let me know if that helps~ – LoLance Apr 30 '20 at 09:19
  • It did, thank you. It is kind of strange that the pre-build event should have a dedicated . – Silviu Preda Apr 30 '20 at 11:14
  • Glad to know it makes some helps :) – LoLance May 01 '20 at 01:32