Reputation: 833
I have a .net solution that I can build with msbuild
and successfully generate a deploy package with a PublishProfile.pubxml
transform for deploying to a single web server.
I need to take that build and generate deploy packages for different environments, which are set up as transforms using various .pubxml
profile files.
I know I could build each profile separately, and it'd be negligible risk of injecting a change into a build, but it's time and space that aren't necessary to consume. I would only end up keeping one of them anyway, and just copying the unique web.config
s from each transform into their own deploy package's folder (sorry if this isn't clear, happy to clarify).
I'm looking for something like this pseudocode, which I know is syntactically incorrect but should get the point across:
// step 1
msbuild myapp.csproj target=Build
// step 2
foreach ($profile in $profileList) {
msbuild myapp.csproj outputdir="releaseDir/$profile" target=Publish publishProfile=$profile
}
I am working in a Jenkins context and can't use Visual Studio functions unless they're available as command-line options.
I've also tried desperately to get msdeploy
to work, which I think might simplify some of this, but for the life of me I can't get it to work with the tempAgent
option, which is really the only way I want to go in my environment. Details on that particular struggle here.
Thanks in advance!
Update 1: This post works well for me, but as I say in a comment, it's still creating multiple deploy packages that take up a ton of space and aren't necessary. What I'd really like is a way to use a single build artifact and create multiple transforms of the Web.config files. Then on deploy, copy that build artifact and the appropriate config file. That would really be build-once/deploy-many!
FWIW, this is the code i came up with using the link above:
function Initialize-Build {
$ErrorActionPreference = 'Stop'
$appName = 'myApp'
$projsToBuild = 'Ui', 'DataService'
$projPath = "$appName/$appName"
$buildPath = 'obj/Release/Package/'
$releasePath = 'Release-Packages'
$commonArgs = '/p:Configuration=Release',
'/nologo',
'/verbosity:quiet'
}
function Invoke-Build {
foreach ($proj in $projsToBuild) {
$projName = $proj -eq 'Ui' ? 'WebUi' : $proj
$p = "$projPath.$proj/$appName.$projName.csproj"
$buildArgs = '/t:Clean,Build',
'/p:AutoParameterizationWebConfigConnectionStrings=False'
Write-Output "Building $p"
msbuild $p @commonArgs @buildArgs
if ($LASTEXITCODE) { exit 1 }
}
}
function Invoke-Transform {
$xformArgs = "/p:deployOnBuild=True", "/p:Targets=Publish"
foreach ($proj in $projsToBuild) {
$p = "$projPath.$proj/$appName.$projName.csproj"
$pubProfiles = 'Dev', 'QA', 'UAT', 'Prod'
foreach ($prof in $pubProfiles) {
Write-Output "Building $p ($prof)"
$pubProfileArg = "/p:PublishProfile=$prof"
msbuild $p @commonArgs @xformArgs $pubProfileArg
if ($LASTEXITCODE) { exit 1 }
}
}
}
. Initialize-PrivLogBuild
Invoke-Build
Invoke-Transform
Upvotes: 3
Views: 1057
Reputation: 833
I realized I wasn't really asking the right question. When I started searching for msbuild transform posts, I found a way to do what I need.
I landed on updating the .csproj files of the apps I'm building with an AfterBuild
target.
There are 4 transforms required, each with their own .config file as the transform source. I was fortunate that these files had already been created by the application developer.
This is the code I ended up with, placed at the end of the .csproj file, inside the </project>
tag. To reduce repetition of paths and filenames, I created configDir
and xformFile
properties. I like this pattern because it's easily scalable and generic!
<!-- all the rest of the .csproj above this -->
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath32)/Microsoft/VisualStudio/v16.0/Web/Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<PropertyGroup>
<configDir>../../Release-Packages/configs</configDir>
<xformFile>Web.config</xformFile>
</PropertyGroup>
<MakeDir Directories="$(configDir)" />
<TransformXml Source="$(xformFile)"
Transform="Web.Dev.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).DEV" />
<TransformXml Source="$(xformFile)"
Transform="Web.QA.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).QA" />
<TransformXml Source="$(xformFile)"
Transform="Web.Prod.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).Prod" />
<TransformXml Source="$(xformFile)"
Transform="Web.UAT.config"
Destination="$(configDir)/$(AssemblyName).$(xformFile).UAT" />
</Target>
</Project>
many thanks to these posts for lighting the way to this solution
Upvotes: 2