Build/Release 使用配置转换在 VSTS 上使用 MSI 部署桌面应用程序

Build/Release flow on VSTS with MSI deployed desktop app using configuration transforms

我们正在为我们的客户端部署的桌面应用程序 (winforms) 实施 DevOps 策略。到目前为止,我们使用 SlowCheetah 进行配置转换(例如:来自配置管理器的 select QA,app.QA.config 自动换入,进行构建,使用 SCCM 将 MSI 部署到 QA 机器)。

我们正在尝试利用 Azure DevOps 来自动执行此过程,但我遇到了 运行 障碍。我想进行 1 次构建,以及 Dev --> QA --> UA --> Prod 的发布管道,但由于配置转换仅 运行 构建,我不确定如何执行此操作。

MSI 只会为当前 selected 配置生成,因此发布步骤中的下降只会有 1 个 MSI(配置已经打包,无法更改)。

我知道让构建步骤构建解决方案 4 次(每个配置一次)会起作用 - drop 将包含所有 4 个 MSI,但这看起来很愚蠢。

我不能只在发布管道上构建安装项目,因为 Drop 中只有 DLL 可用,项目文件不可用。我怎样才能做到这一点?

谢谢!

要在发布管道中执行此操作,您实际上只有几个选择:

  1. 拆开 MSI 并重新导入正确的配置并重新打包(不知道这会有多容易,因为我不了解 MSI,但已将此方法用于其他包实际上是 .zip)

  2. 在发布管道中构建包。你说文件在 drop 中不可用,但你可以从你的构建管道中控制它(假设这也是使用 Azure Pipelines 完成的)。因此,您可以更改您的管道以将所需的文件(使用复制任务)复制到您创建放置的位置,通常是 $(build.artifactstagingdirectory)。或者,如果您不想将这些文件混合到您的 drop 中,您可以创建第二个工件 drop(只需为此放入另一个发布工件任务)。如果我选择这条路线,我会将今天 $(build.artifactstagingdirectory) 中的文件复制到 $(build.artifactstagingdirectory)/packagefiles 中,并将将 MSI 打包到 $(build.artifactstagingdirectory)/projectfiles 中所需的项目文件并将两个发布工件任务指向这些目录之一。

一旦您获得了包括用于构建 MSI 的文件在内的文件,您将需要在正确的配置中替换任务,然后是 MSI 打包任务,您应该完成了。

我们从包含 WiX 安装程序项目的 Visual Studio 解决方案构建 MSI 时遇到了完全相同的问题,在 app.config 上使用配置转换来替换配置。

正如您所建议的,我们最初沿着 运行ning Azure DevOps 构建管道的路线,为解决方案中的每个配置进行多次构建,但这很快变得不雅和浪费,因为我们不仅需要为 (dev/stage/qa/live) 构建,但也有应用于多个客户的配置,最终在解决方案中有 12 多个配置,并且构建时间非常长。

替换 MSI 中的配置

正如之前的回答中提到的,我们最终得到的解决方案是在构建管道中仅构建一次 MSI,将 MSI 连同我们所有的替换 app.config 文件复制到放置文件夹,然后 运行 发布管道中的自定义应用程序以强制替换 MSI 中的 Application.exe.config。不幸的是,这并不像在发布任务中 'unzipping the MSI' 替换配置然后 're-zipping' 那样简单,因为 MSI 使用自定义文件格式并维护需要正确修改的内部数据库。

我们最终使用 this stack overflow answer 中发布的方法创建了一个自定义 C# .NET 控制台应用程序,然后我们将其托管在我们的本地构建代理上,以便我们可以 运行 一个简单的 powershell我们的发布管道中的任务使用一些相关参数调用我们的自定义控制台应用程序:

"C:\BuildTools\msi_replace_file.exe" -workingfolder "$(System.DefaultWorkingDirectory)/_BuildOutput/drop/Application.Installer/bin/Release/" -msi "Application.Installer.msi" -config "Application.exe.config" 

然后我们为每个 'configuration' 执行以下基本步骤的发布管道阶段:

in this question, but we chose to create a C# application using the utilities within the Microsoft.Deployment.* namespace that are provided as part of the WiX Toolset 所述,还有多种其他方法可以替换 MSI 中的文件。这将保证与我们最初用于构建安装程序的 WiX 版本的兼容性,并使我们能够完全控制该过程。但是,我很欣赏这种方法非常脆弱(我对此并不满意)并且不是特别可扩展,因为它依赖于在我们的本地构建代理上托管的自定义工具。我打算在未来改进这一点。

您还应该知道,以这种方式破解 MSI 可能会在未来引起问题,尤其是当您更改工具链或升级到更高版本的 WiX 时。

从发布管道构建 MSI

我个人不喜欢将所需 dlls/assets 复制到放置位置然后 'building' 发布管道中的 MSI 的想法,因为对我们来说构建 WiX 项目的行为是我们 'build process' 的很大一部分,并已集成到我们的 visual studio 解决方案中,因此感觉将 MSI 的创建移动到发布管道是违反直觉的,并且还可能需要我们创建自定义任务运行 WiX CLI 工具(heat.exe、light.exe、candle.exe)针对我们的 WXS 文件版本的构建代理,或者具有仅构建 wixproj 文件的构建步骤整个解决方案。但是,我可以看到这种替代方法如何适用于其他人,并且我认为根据您的情况同样有效。

几年前我们所做的是维护一个包含所有环境配置文件的 sub-folder。在安装时使用自定义操作并在命令行上提供特定环境,自定义操作将从 configFils.zip.

中的环境匹配文件夹中提取配置文件

ConfigFiles.zip 文件中的文件夹结构与此类似。

/Dev1/app.config
/Dev2/app.config
/Prod/app.config

MsiExec.exe /i YourMSI.msi /TargetDir=C:\Yourfolder /Config=Prod  

自定义操作将从 Prod 文件夹中提取并放置 app.config

另一种方法:

您可以在运行时动态配置您的应用,而不是在 App.config 或其任何转换中放置依赖于环境的设置。

然而,这将需要您的应用从目标系统获得一些线索,以便它知道它在哪个环境或哪个主机上 运行。

示例: ASP.NET 核心应用程序假定存在“ASPNETCORE_ENVIRONMENT”环境变量。如果它不存在,应用程序会假定它在生产环境中运行。 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-5.0

无论如何,提供这样的环境变量应该不会在您访问主机时造成问题。 只需在发布管道的开头添加一个步骤来设置环境变量并将其值设置为您尝试部署到的阶段的名称 (development/testing/etc)。

这样您就可以在构建管道中构建一次 MSI 并部署到任意多的环境中。

当然,这需要您提前为该目标环境准备您的应用程序。