Настройка конвейера CI/CD с помощью файла YAML

В таблице ниже перечислены различные аргументы MSBuild, которые можно определить для настройки конвейера сборки.

Аргумент MSBuild Ценность Описание
AppxPackageDir $(Build.ArtifactStagingDirectory)\AppxPackages Определяет папку для хранения созданных артефактов.
AppxBundlePlatforms $(Build.BuildPlatform) Позволяет указать платформы, в которые будет включен пакет.
AppxBundle Всегда Создает пакет MSIXBUNDLE или APPXBUNDLE, содержащий файлы MSIX или APPX, для указанной платформы.
UapAppxPackageBuildMode StoreUpload Генерирует файл .msixupload/.appxupload и папку _Test для боковой загрузки.
UapAppxPackageBuildMode СИ Генерирует только файл .msixupload или .appxupload.
UapAppxPackageBuildMode Только сторонняя загрузка Создает папку _Test только для боковой загрузки.
AppxPackageSigningEnabled (Включено Подписание Пакетов Appx) истина Включает подписывание пакетов.
Отпечаток сертификата пакета Отпечаток сертификата Это значение должно соответствовать отпечатку в сертификате для подписи, или строка должна быть пустой.
Файл ключа сертификата пакета Путь Путь к сертификату для использования. Это значение извлекается из метаданных защищенного файла.
Пароль для сертификата пакета Пароль Пароль для закрытого ключа в сертификате. Рекомендуется сохранить пароль в Azure Key Vault и связать пароль с группой переменных. Можно передать переменную в этот аргумент.

Прежде чем создать проект упаковки тем же способом, что и мастер Visual Studio, используя командную строку MSBuild, процесс сборки может задать версию для создаваемого пакета MSIX, изменив атрибут Version элемента Package в файле Package.appxmanifest. В Azure Pipelines это можно сделать с помощью выражения, указав переменную счетчика, значение которой будет увеличиваться для каждой сборки, и скрипта PowerShell, который использует класс System.Xml.Linq.XDocument в .NET, чтобы изменить значения атрибута.

Пример файла YAML, определяющего конвейер сборки MSIX

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), конвейеру необходимо получить сертификат для подписи. Для этого добавьте задачу DownloadSecureFile перед задачей VSBuild. Это обеспечит доступ к сертификату подписи с помощью 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)'

Созданные артефакты можно просмотреть в параметре Артефакты на странице результатов сборки.

Файл Установщика приложений для распространения вне магазина

Если вы распространяете приложение за пределами Магазина, для установки и обновления пакета можно воспользоваться файлом Установщика приложений.

Файл APPINSTALLER будет искать обновленные файлы в репозитории \server\foo.

<?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 сообщает системе периодичность проверки наличия обновлений, а также о необходимости принудительного обновления пользователем. Полное справочное руководство по схемам, включая список поддерживаемых пространств имен для каждой версии Windows 10, можно найти в документации по адресу bit.ly/2TGWnCR.

Если добавить .appinstaller файл в проект упаковки и задать для свойства "Действие пакета" значение "Содержимое", а для свойства "Копировать в выходной каталог" — "Копировать, если новее", то можно добавить еще одну задачу PowerShell в файл YAML, которая будет обновлять атрибуты версии корневого элемента и элемента MainPackage и сохранять обновленный файл в staging каталоге.

- 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 на этапе выпуска, чтобы динамически изменить значения двух атрибутов Uri в файле .appinstaller так, чтобы они отражали местоположение, в которое публикуется приложение.

Ниже приведена задача конвейера выпуска, которая изменяет коды URI в файле APPINSTALLER:

- 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 указан UNC-путь к общей папке Azure. В этом случае операционная система будет искать пакет 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, можно опубликовать файлы во внутренней сетевой папке.

Если вы решите публиковать на веб-сервере, вы можете указать MSBuild сгенерировать файл .appinstaller с версией и HTML-страницу, содержащую ссылку для скачивания и некоторую информацию об упакованном приложении, добавив несколько дополнительных аргументов в файл YAML:

- 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>

Если вы настроили конвейер релиза, который публикует содержимое папки сброса на вашу интрасеть или любой другой веб-сайт, а веб-сервер поддерживает запросы с указанным диапазоном байтов и правильно настроен, ваши пользователи смогут использовать эту ссылку для прямой установки приложения без предварительного скачивания MSIX пакета.

Примечание.

Возможность использовать схему URI ms-appinstaller (универсальный идентификатор ресурса) (протокол) можно управлять ИТ-специалистом (администратором). Чтобы включить ms-appinstaller в сети, установите для параметра Group Policy EnableMSAppInstallerProtocol (/windows/client-management/mdm/policy-csp-desktopappinstaller) значение enabled (см . раздел "Политика CSP - DesktopAppInstaller"). Дополнительные сведения см. в статье об установке приложений Windows 10 с веб-страницы.