用 YAML 文件配置 CI/CD 管道
下表列出了可以定义用来设置生成管道的各个 MSBuild 参数。
MSBuild 参数 | 值 | 描述 |
---|---|---|
AppxPackageDir | $(Build.ArtifactStagingDirectory)\AppxPackages | 定义要存储生成的项目的文件夹。 |
AppxBundlePlatforms | $(Build.BuildPlatform) | 用于定义要包含在捆绑包中的平台。 |
AppxBundle | 始终 | 使用 .msix/.appx 文件为指定的平台创建 .msixbundle/.appxbundle。 |
UapAppxPackageBuildMode | StoreUpload | 生成要旁加载的 .msixupload/.appxupload 文件和 _Test 文件夹。 |
UapAppxPackageBuildMode | CI | 仅生成 .msixupload/.appxupload 文件。 |
UapAppxPackageBuildMode | SideloadOnly | 仅生成要旁加载的 _Test 文件夹。 |
AppxPackageSigningEnabled | true | 启用包签名。 |
PackageCertificateThumbprint | 证书指纹 | 此值必须与签名证书中的指纹匹配,或者为空字符串。 |
PackageCertificateKeyFile | 路径 | 要使用的证书的路径。 此值是从安全文件元数据中检索的。 |
PackageCertificatePassword | 密码 | 证书中私钥的密码。 建议将密码存储在 Azure Key Vault 中,并将密码链接到变量组。 可将变量传递到此参数。 |
在使用 MSBuild 命令行生成打包项目(就像在 Visual Studio 中使用向导生成项目一样)之前,生成过程可以通过编辑 Package.appxmanifest 文件中 Package 元素的 Version 属性,来对生成的 MSIX 包进行版本控制。 在 Azure Pipelines 中,可以使用某个表达式来实现此目的,该表达式可以设置每次生成都会递增的计数器变量。也可以通过某个 PowerShell 脚本来实现此目的,该脚本使用 .NET 中的 System.Xml.Linq.XDocument 类来更改该属性的值。
用于定义 MSIX 生成管道的示例 YAML 文件
pool:
vmImage: windows-2019
variables:
buildPlatform: 'x86'
buildConfiguration: 'release'
major: 1
minor: 0
build: 0
revision: $[counter('rev', 0)]
steps:
- powershell: |
# Update appxmanifest. This must be done before the build.
[xml]$manifest= get-content ".\Msix\Package.appxmanifest"
$manifest.Package.Identity.Version = "$(major).$(minor).$(build).$(revision)"
$manifest.save("Msix/Package.appxmanifest")
displayName: 'Version Package Manifest'
- task: MSBuild@1
inputs:
solution: Msix/Msix.wapproj
platform: $(buildPlatform)
configuration: $(buildConfiguration)
msbuildArguments: '/p:OutputPath=NonPackagedApp
/p:UapAppxPackageBuildMode=SideLoadOnly /p:AppxBundle=Never /p:AppxPackageOutput=$(Build.ArtifactStagingDirectory)\MsixDesktopApp.msix /p:AppxPackageSigningEnabled=false'
displayName: 'Package the App'
- task: DownloadSecureFile@1
inputs:
secureFile: 'certificate.pfx'
displayName: 'Download Secure PFX File'
- script: '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\signtool"
sign /fd SHA256 /f $(Agent.TempDirectory)/certificate.pfx /p secret $(
Build.ArtifactStagingDirectory)/MsixDesktopApp.msix'
displayName: 'Sign MSIX Package'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'
下面是 YAMl 文件中定义的不同生成任务的细分:
配置包生成属性
以下定义设置生成组件的目录、平台,并定义是否生成捆绑包。
/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)\AppxPackages\"
/p:UapAppxPackageBuildMode=SideLoadOnly
/p:AppxBundlePlatforms="$(Build.BuildPlatform)"
/p:AppxBundle=Never
配置包签名
若要为 MSIX(或 APPX)包签名,管道需要检索签名证书。 为此,请在 VSBuild 任务的前面添加 DownloadSecureFile 任务。
这样,就可以通过 signingCert
访问签名证书。
- task: DownloadSecureFile@1
name: signingCert
displayName: 'Download CA certificate'
inputs:
secureFile: '[Your_Pfx].pfx'
接下来,更新 MSBuild 任务以引用签名证书:
- task: MSBuild@1
inputs:
platform: 'x86'
solution: '$(solution)'
configuration: '$(buildConfiguration)'
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)"
/p:AppxPackageDir="$(appxPackageDir)"
/p:AppxBundle=Never
p:UapAppxPackageBuildMode=SideLoadOnly
/p:AppxPackageSigningEnabled=true
/p:PackageCertificateThumbprint=""
/p:PackageCertificateKeyFile="$(signingCert.secureFilePath)"'
注意
PackageCertificateThumbprint 参数被有意设置为空字符串,目的是引以注意。 如果在项目中设置指纹,但该指纹与签名证书不匹配,则生成将会失败并出现错误:Certificate does not match supplied signing thumbprint
。
查看参数
使用 $()
语法定义的参数是在生成定义中定义的变量,在其他生成系统中将会更改。
若要查看所有预定义的变量,请参阅预定义的生成变量。
配置“发布生成项目”任务
默认的 MSIX 管道不会保存生成的项目。 若要将发布功能添加到 YAML 定义,请添加以下任务。
- task: CopyFiles@2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
inputs:
SourceFolder: '$(system.defaultworkingdirectory)'
Contents: '**\bin\$(BuildConfiguration)\**'
TargetFolder: '$(build.artifactstagingdirectory)'
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)'
可以在生成结果页的“项目”选项中查看生成的项目。
非 Store 分发内容的 AppInstaller 文件
如果在 Store 的外部分发应用程序,可以利用 AppInstaller 文件来安装和更新包
一个可在 \server\foo 上查找更新文件的 .appinstaller 文件
<?xml version="1.0" encoding="utf-8"?>
<AppInstaller xmlns="http://schemas.microsoft.com/appx/appinstaller/2018"
Version="1.0.0.0"
Uri="\\server\foo\MsixDesktopApp.appinstaller">
<MainPackage Name="MyCompany.MySampleApp"
Publisher="CN=MyCompany, O=MyCompany, L=Stockholm, S=N/A, C=Sweden"
Version="1.0.0.0"
Uri="\\server\foo\MsixDesktopApp.msix"
ProcessorArchitecture="x86"/>
<UpdateSettings>
<OnLaunch HoursBetweenUpdateChecks="0" />
</UpdateSettings>
</AppInstaller>
UpdateSettings 元素用于告知系统何时检查更新,以及是否强制用户更新。 可以在 bit.ly/2TGWnCR 上的文档中找到完整的架构参考,包括每个 Windows 10 版本支持的命名空间。
如果将 .appinstaller 文件添加到打包项目,并将其“打包操作”属性设置为“内容”,将“复制到输出目录”属性设置为“如果较新则复制”,则可以将另一个 PowerShell 任务添加到 YAML 文件,以便更新 root 和 MainPackage 元素的 Version 属性,并将更新的文件保存到暂存目录:
- powershell: |
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
$doc = [System.Xml.Linq.XDocument]::Load(
"$(Build.SourcesDirectory)/Msix/Package.appinstaller")
$version = "$(major).$(minor).$(build).$(revision)"
$doc.Root.Attribute("Version").Value = $version;
$xName =
[System.Xml.Linq.XName]
"{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
$doc.Root.Element($xName).Attribute("Version").Value = $version;
$doc.Save("$(Build.ArtifactStagingDirectory)/MsixDesktopApp.appinstaller")
displayName: 'Version App Installer File'
然后,将 .appinstaller 文件分发给最终用户,并让他们双击此文件而不是 .msix 文件来安装打包的应用。
持续部署
应用安装程序文件本身是未编译的 XML 文件,生成后可按需编辑该文件。 这样,在将软件部署到多个环境,以及想要将生成管道与发布过程区分开来时,就可以轻松地使用该文件。
如果在 Azure 门户中使用“空作业”模板创建发布管道,并使用最近设置的生成管道作为要部署的项目的源,则可以将 PowerShell 任务添加到发布阶段,以动态更改 .appinstaller 文件中两个 Uri 属性的值,来反映应用发布到的位置。
一个用于修改 .appinstaller 文件中的 URI 的发布管道任务
- powershell: |
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
$fileShare = "\\filesharestorageccount.file.core.windows.net\myfileshare\"
$localFilePath =
"$(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop\MsixDesktopApp.appinstaller"
$doc = [System.Xml.Linq.XDocument]::Load("$localFilePath")
$doc.Root.Attribute("Uri").Value = [string]::Format('{0}{1}', $fileShare,
'MsixDesktopApp.appinstaller')
$xName =
[System.Xml.Linq.XName]"{http://schemas.microsoft.com/appx/appinstaller/2018}MainPackage"
$doc.Root.Element($xName).Attribute("Uri").Value = [string]::Format('{0}{1}',
$fileShare, 'MsixDesktopApp.appx')
$doc.Save("$localFilePath")
displayName: 'Modify URIs in App Installer File'
在上述任务中,URI 设置为 Azure 文件共享的 UNC 路径。 由于在安装和更新应用时,OS 将在此位置查找 MSIX 包,因此,我还将另一个命令行脚本添加到了发布管道,该脚本首先将云中的文件共享映射到生成代理上的本地 Z:\ 驱动器,然后使用 xcopy 命令将 .appinstaller 和 .msix 文件复制到该驱动器:
- script: |
net use Z: \\filesharestorageccount.file.core.windows.net\myfileshare
/u:AZURE\filesharestorageccount
3PTYC+ociHIwNgCnyg7zsWoKBxRmkEc4Aew4FMzbpUl/
dydo/3HVnl71XPe0uWxQcLddEUuq0fN8Ltcpc0LYeg==
xcopy $(System.DefaultWorkingDirectory)\_MsixDesktopApp\drop Z:\ /Y
displayName: 'Publish App Installer File and MSIX package'
如果你托管了自己的本地 Azure DevOps Server,当然可以将文件发布到自己的内部网络共享。
如果选择发布到 Web 服务器,可以通过在 YAML 文件中提供一些附加的参数,来告知 MSBuild 生成版本受控的 .appinstaller 文件和一个 HTML 页面,该页面包含下载链接,以及一些有关打包的应用的信息:
- task: MSBuild@1
inputs:
solution: Msix/Msix.wapproj
platform: $(buildPlatform)
configuration: $(buildConfiguration)
msbuildArguments: '/p:OutputPath=NonPackagedApp /p:UapAppxPackageBuildMode=SideLoadOnly /p:AppxBundle=Never /p:GenerateAppInstallerFile=True
/p:AppInstallerUri=http://yourwebsite.com/packages/ /p:AppInstallerCheckForUpdateFrequency=OnApplicationRun /p:AppInstallerUpdateFrequency=1 /p:AppxPackageDir=$(Build.ArtifactStagingDirectory)/'
displayName: 'Package the App'
生成的 HTML 文件包含一个超链接,该链接以不区分浏览器的 ms-appinstaller 协议激活方案为前缀:
<a href="ms-appinstaller:?source=
http://yourwebsite.com/packages/Msix_x86.appinstaller ">Install App</a>
如果设置发布管道用于将放置文件夹的内容发布到 Intranet 或任何其他网站,且 Web 服务器支持字节范围请求并已正确配置,则最终用户可以使用此链接直接安装应用,而无需先下载 MSIX 包。
注意
IT 专业人员(管理员)可以控制使用 ms-appinstaller URI(统一资源标识符)方案(协议)。 若要在网络中启动 ms-appinstaller,请将组策略 EnableMSAppInstallerProtocol (/windows/client-management/mdm/policy-csp-desktopappinstaller) 设置为启用(请参阅策略 CSP - DesktopAppInstaller)。 有关更多信息,请参阅从网页安装 Windows 10 应用。