HodorNV / ALOps

ALOps
59 stars 24 forks source link

[FEATURE REQUEST] AppSource Validation functions #551

Closed Arthurvdv closed 11 months ago

Arthurvdv commented 2 years ago

Version 4.0.0 of the BcContainerHelper comes with a set of functions to automate the release to AppSource process.

Added AppSource Validation functions
New functions Invoke-IngestionAPIGet, Invoke-IngestionAPIGetCollection, Invoke-IngestionAPIPost, Invoke-IngestionAPIPut, Invoke-IngestionAPIDelete to interact with Partner Center Ingestion API
New function Get-AppSourceProducts to get a list of all products on AppoSource belonging to a specific account
New function Get-AppSourceProduct to get detailed information about a product on AppSource
New function Get-AppSourceSubmission to get detailed information about a submission of a product on AppSource
New function New-AppSourceSubmission to create a submission of a new version of a product on AppSource
New function Promote-AppSourceSubmission to promote a submission of a product on AppSource from preview to live / production
New function Cancel-AppSourceSubmission to cancel an in progress submission of a product on AppSource

What is the best approach for us as ALOps customer?

  1. Wait for ALOps to create a implementation of this API?
  2. Wait for ALOps to create a wrapper around these BCCH functions
  3. Use Powershell and BCCH to accomplish these steps in our release pipeline
  4. Something else?
waldo1001 commented 2 years ago

We will look into the API's from Partner Center, but relying on undocumented, unsupported, ever-changing powershell scripts from 1 guy, is something that has failed on us more than once :(.

We can't seem to find the API documentation for AppSource submission - if you have any references, that would be really helpful.

Arthurvdv commented 2 years ago

While I can understand your restraint, I think we both can agree on that it would be awesome if ALOps could support this.

There is a Swagger file over here: https://ingestionapi-swagger.azureedge.net.

In the podcast Window on Technology - Freddy Kristiansen - CI/CD and Containers Freddy explains that the frontend of Partner Center also uses this ingestion API als backend. He contacted the team that created the API, figured out how the API works and implemented this in the BcContainerHelper.

We could reach out to Freddy or reverse engineer the API-calls from the BcContainerHelper?

fvet commented 2 years ago

I would be in favor of option 2 (ALOps providing a wrapper around BCCH). I'd suppose MS would also use the BCCH commandlets to improve their own AL-Go on github, so seems logic that ALOps would build further on top of these commands so we can close the last gap for automated AppSource releases ;)

Arthurvdv commented 2 years ago

image

For now we've decided to use the BcContainerHelper with some PowerShell scripting to implement this feature.

I'm not a PowerShell-guru, but tried to make the code als readable as possible. There are some assumptions in the example below, so can't guarantee this wil work for everybody. Also there are some custom steps above that grabs all the dependency apps from our Azure DevOps Artifacts Feed and places these in the subfolder Library.

image

We decided that the Alias (in the Offer Setup) needs to match with the name in the App.json to prevent a mapping table somewhere between the AppId and the OfferId from the Marketplace (and needs to be unique). If there's a better way of handeling this I would love to know.

Posting it here to share with the community!

- task: PowerShell@2
  displayName: 'New AppSource Submission'
  condition: succeeded()
  env:
    BUILD_BINARIESDIRECTORY: $(Build.BinariesDirectory)
  inputs:
    targetType: 'inline'
    script: |
      Import-Module 'D365BCAppHelper'
      Import-Module 'BcContainerHelper'

      $appFile = Get-ChildItem -Path $env:BUILD_BINARIESDIRECTORY -Depth 0 -Filter *.app | Select-Object -First 1 | % { $_.FullName }

      if (!(Test-Path $appFile)) {
          throw "Unable to find $appFile"
      }

      Write-Host "Extracting App manifest from $appFile"
      $xmlManifest = Get-D365BCManifestFromAppFile -Filename $appFile

      Write-Host "**************************************"
      Write-Host "$($spaces)* App File = [$($appFile)]"
      Write-Host "$($spaces)"
      Write-Host "$($spaces)* App.ID        = $($xmlManifest.App.Id)"
      Write-Host "$($spaces)* App.Name      = $($xmlManifest.App.Name)"
      Write-Host "$($spaces)* App.Publisher = $($xmlManifest.App.Publisher)"
      Write-Host "$($spaces)* App.Version   = $($xmlManifest.App.Version)"
      Write-Host "$($spaces)"
      Write-Host "$($spaces)"

      Write-Host "Search for '$($xmlManifest.App.Name)' in Marketplace offers on Microsoft Partner Center"

      $authcontext = New-BcAuthContext `
      -clientID $clientId `
      -clientSecret $clientSecret `
      -tenantID $tenantId `
      -scopes 'https://api.partner.microsoft.com/.default'

      $products = Get-AppSourceProduct -authContext $authcontext -silent
      $product = ($products | Where-Object { $_.name -eq "$($xmlManifest.App.Name)" -and $_.resourceType -eq 'AzureDynamics365BusinessCentral' })
      if ($null -eq $product) {
         throw "No Marketplace offer with the name '$($xmlManifest.App.Name)' found on Microsoft Partner Center."
      }
      else {
         Write-Host "Found marketplace offer id '$($product.Id)' for App '$($xmlManifest.App.Name)'"
      }

      $appHasLibraryApps = $false
      $libraryAppsFolder = Join-Path $env:BUILD_BINARIESDIRECTORY 'Library'

      if (Test-Path $libraryAppsFolder) {
          $apps = Get-ChildItem -Path $libraryAppsFolder -Filter *.app -Recurse

          if ($apps.Count -ne 0) {
              $appHasLibraryApps = $true
          }

          $libraryAppFiles = @()
          $apps | % { $libraryAppFiles += $($_.FullName) }
      }

      if ($appHasLibraryApps) {
          # App with Library apps
          Write-Host "New-AppSourceSubmission -authContext $authcontext -productId $($product.Id) -appFile $appFile -libraryAppFiles $libraryAppFiles -autoPromote -doNotWait"
          New-AppSourceSubmission -authContext $authcontext -productId $($product.Id) -appFile $appFile -libraryAppFiles $libraryAppFiles -autoPromote -doNotWait
      }
      else {
          # App without Library apps
          Write-Host "New-AppSourceSubmission -authContext $authcontext -productId $($product.Id) -appFile $appFile -autoPromote -doNotWait"
          New-AppSourceSubmission -authContext $authcontext -productId $($product.Id) -appFile $appFile -autoPromote -doNotWait
      }
waldo1001 commented 2 years ago

Thanks for this.

We'll look into the Swagger and see what we can do from there!

MortenRa commented 1 year ago

@waldo1001 Any progress in this

waldo1001 commented 1 year ago

In fact - we finally have a working prototype.. . Good things are coming ..

The provided information in this post was very helpful. Thanks so much.

CarloAxians commented 1 year ago

Hi @waldo1001, Just curious, what's the status of this ticket? I had to do a submission today.

waldo1001 commented 1 year ago

We're testing the first alfa version of this on our own AppSource apps .. so we're finalizing...

MortenRa commented 1 year ago

@waldo1001 are we now in beta test ?

waldo1001 commented 1 year ago

We tested it, it failed (minimal changes) - and we're about to re-test - so yes, we're in beta. Almost there...

waldo1001 commented 1 year ago

Good news: AppSource update is coming to the next version.