Configurare la pipeline CI/CD con il file YAML

La tabella seguente elenca i diversi argomenti di MSBuild che puoi definire per configurare la pipeline di compilazione.

Argomento di MSBuild Valore Descrizione
AppxPackageDir $(Build.ArtifactStagingDirectory)\AppxPackages Definisce la cartella in cui archiviare gli elementi generati.
AppxBundlePlatforms $(Build.BuildPlatform) Ti consente di definire le piattaforme da includere nel bundle.
AppxBundle Sempre Crea un file con estensione msixbundle o appxbundle con i file con estensione msix o appx per la piattaforma specificata.
UapAppxPackageBuildMode StoreUpload Genera il file con estensione msixupload o appxupload e la cartella _Test per il trasferimento locale.
UapAppxPackageBuildMode CI Genera solo il file con estensione msixupload o appxupload.
UapAppxPackageBuildMode SideloadOnly Genera solo la cartella _Test per il trasferimento locale.
AppxPackageSigningEnabled True Abilita la firma del pacchetto.
PackageCertificateThumbprint Identificazione personale del certificato Questo valore deve corrispondere all'identificazione personale nel certificato di firma oppure la stringa deve essere vuota.
PackageCertificateKeyFile Path Percorso del certificato da usare. Viene recuperato dai metadati del file protetto.
PackageCertificatePassword Password Password per la chiave privata del certificato. Consigliamo di archiviare la password in Azure Key Vault e collegarla a un gruppo di variabili. Puoi passare la variabile a questo argomento.

Prima di compilare il progetto di creazione del pacchetto come fa la procedura guidata di Visual Studio tramite la riga di comando di MSBuild, il processo di compilazione può eseguire il controllo della versione del pacchetto MSIX generato modificando l'attributo Version dell'elemento Package nel file Package.appxmanifest. In Azure Pipelines è possibile ottenere questo risultato usando un'espressione per impostare una variabile contatore che viene incrementata ad ogni compilazione e uno script di PowerShell che usa la classe System.Xml.Linq.XDocument in .NET per modificare il valore dell'attributo.

File YAML di esempio che definisce la pipeline di compilazione 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'

Di seguito sono riportate le scomposizioni delle diverse attività di compilazione definite nel file YAML:

Configurare le proprietà di generazione del pacchetto

La definizione seguente imposta la directory dei componenti di build, la piattaforma e definisce se deve essere compilato o meno un bundle.

/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)\AppxPackages\"
/p:UapAppxPackageBuildMode=SideLoadOnly
/p:AppxBundlePlatforms="$(Build.BuildPlatform)"
/p:AppxBundle=Never

Configurare la firma del pacchetto

Per firmare il pacchetto MSIX o APPX, la pipeline deve recuperare il certificato di firma. A tale scopo, aggiungi un'attività DownloadSecureFile prima dell'attività VSBuild. In questo modo, potrai accedere al certificato di firma tramite signingCert.

- task: DownloadSecureFile@1
  name: signingCert
  displayName: 'Download CA certificate'
  inputs:
    secureFile: '[Your_Pfx].pfx'

Aggiorna quindi l'attività MSBuild in modo da fare riferimento al certificato di firma:

- 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)"'

Nota

Come precauzione, l'argomento PackageCertificateThumbprint viene intenzionalmente lasciato vuoto. Se l'identificazione personale è impostata nel progetto ma non corrisponde al certificato di firma, la build non verrà eseguita e verrà visualizzato l'errore: Certificate does not match supplied signing thumbprint.

Verificare i parametri

I parametri definiti con la sintassi $() sono variabili specificate nella definizione della build e saranno diversi in altri sistemi di compilazione.

Per visualizzare tutte le variabili predefinite, vedi Variabili di compilazione predefinite.

Configurare l'attività Pubblica artefatti di compilazione

La pipeline MSIX predefinita non salva gli artefatti generati. Per aggiungere le funzionalità di pubblicazione alla definizione YAML, aggiungi le attività seguenti.

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

Puoi visualizzare gli artefatti generati nell'opzione Artefatti della pagina relativa ai risultati della compilazione.

File AppInstaller per la distribuzione non nello Store

Se stai distribuendo l'applicazione all'esterno dello Store, puoi sfruttare il file AppInstaller per l'installazione e gli aggiornamenti del pacchetto.

File con estensione appinstaller che cerca i file aggiornati in \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>

L'elemento UpdateSettings viene usato per indicare al sistema quando verificare la disponibilità di aggiornamenti e se forzare l'esecuzione dell'aggiornamento da parte dell'utente. Per il riferimento dello schema completo, inclusi gli spazi dei nomi supportati per ogni versione di Windows 10, vedi la documentazione in bit.ly/2TGWnCR.

Se aggiungi il file con estensione appinstaller al progetto di creazione del pacchetto e imposti la proprietà Package Action su Content e la proprietà Copy to Output Directory su Copy (se più recente), puoi aggiungere un'altra attività di PowerShell al file YAML che aggiorni gli attributi di Version della radice e gli elementi MainPackage e salvi il file aggiornato nella directory di gestione temporanea:

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

Potresti quindi distribuire il file con estensione appinstaller agli utenti finali e consentire loro di installare l'app in pacchetto facendo doppio clic su questo file anziché su quello con estensione msix.

Distribuzione continua

Il file del programma di installazione dell'app è un file XML non compilato che può essere modificato dopo la build, se necessario. In questo modo, è facile da usare quando distribuisci il software in più ambienti e quando vuoi separare la pipeline di compilazione dal processo di rilascio.

Se crei una pipeline di rilascio nel portale di Azure usando il modello di processo vuoto e usi la pipeline di compilazione recentemente configurata come origine dell'artefatto da distribuire, potrai aggiungere l'attività di PowerShell alla fase di rilascio per modificare dinamicamente i valori dei due attributi Uri nel file con estensione appinstaller in modo da riflettere la posizione in cui viene pubblicata l'app.

Attività della pipeline di rilascio che modifica gli attributi Uri nel file con estensione 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'

Nell'attività precedente l'URI è impostato sul percorso UNC di una condivisione file di Azure. Poiché questo è il punto in cui il sistema operativo cercherà il pacchetto MSIX quando installi e aggiorni l'app, abbiamo aggiunto anche un altro script della riga di comando alla pipeline di rilascio che esegue il mapping della condivisione file nel cloud all'unità Z:\ locale nell'agente di compilazione prima di usare il comando xcopy per copiare i file con estensione appinstaller e 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'

Se ospiti la tua istanza di Azure DevOps Server locale, puoi naturalmente pubblicare i file nella condivisione di rete interna.

Se scegli di eseguire la pubblicazione in un server Web, puoi indicare a MSBuild di generare un file appinstaller con controllo delle versioni, una pagina HTML con un collegamento di download e alcune informazioni sull'app in pacchetto fornendo alcuni argomenti aggiuntivi nel file 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'

Il file HTML generato include un collegamento ipertestuale preceduto dallo schema di attivazione di protocolli di ms-appinstaller indipendente dal browser:

<a href="ms-appinstaller:?source=
  http://yourwebsite.com/packages/Msix_x86.appinstaller ">Install App</a>

Se configuri una pipeline di versione che pubblica il contenuto della cartella di ricezione nella intranet o in un altro sito Web e il server Web supporta le richieste di intervalli di byte ed è configurato correttamente, gli utenti finali possono usare questo collegamento per installare direttamente l'app senza prima scaricare il pacchetto MSIX.