microsoft / navcontainerhelper

Official Microsoft repository for BcContainerHelper, a PowerShell module, which makes it easier to work with Business Central Containers on Docker.
MIT License
389 stars 247 forks source link

Docs on how to handle NuGet Runtime Packages #3590

Open lktraser opened 4 months ago

lktraser commented 4 months ago

Describe the issue Hi this is not an issue in the sense of it's not working but missing documentation or pointers to such documentation.

I'm trying to adopt the NuGet scripts for our CI/CD and had a really hard time figuring out how to run the scripts correctly for Runtimes to work as intented. I'll include my script below because I need someone to tell me if I did this right or if I'm missing the obvious easy path I should have taken. I worked based on the slides from the BC TechDays but even with that information it still took me hours to get it right. I don't think such a fundamental thing should be this hard so we make the barrier of entry lower for better adoption rates.

My proposal would be to A) Write a post for Freddy's Blog on how to Push and Pull Runtimes with NuGet and B) include examples for runtimes in the documentation headers of the Push and Pull Scripts. Some general guidelines on how to setup Feeds, (prelease, release, runtimes, internal, external would also be appreciated)

I would really like to see large scale adoption of this technologie but handling runtimes is still a big part of that and needs to be easy. Ideally there should be a cmdlet/parameter that just does it correctly out of the box.

I've used the slide below to get this far. Is it correct that runtimes can only be pulled with 'Download-BcNuGetPackageToFolder' because 'Get-BcNuGetPackage' doesn't explore the dependencies and therefore will never find the actual apps?

Scripts used to create container and cause the issue Pushing Runtimes:

foreach ($app in $apps.FullName) {
    $appJson = Get-AppJsonFromAppFile -appFile $app

    $packageName = Get-BcNuGetPackageId -publisher $appJson.publisher -name $appJson.name -id $appJson.id -version $appJson.version -tag 'runtime'

    $feed, $packageId, $packageVersion = Find-BcNuGetPackage `
        -nuGetServerUrl $nugetserverurl `
        -nuGetToken $nugetToken `
        -packageName $packageName `
        -version $appJson.version `
        -select Exact

    if ($packageVersion -eq $appJson.version) {
        continue
    }

    $NugetPackage = New-BcNuGetPackage `
        -appfile $app `
        -isIndirectPackage `
        -packageId "{publisher}.{name}.runtime.{id}" `
        -dependencyIdTemplate "{publisher}.{name}.runtime.{id}" #-prereleaseTag 'runtime'

    Push-BcNuGetPackage -nuGetServerUrl $nugetserverurl -nuGetToken $nugetToken -bcNuGetPackage $NugetPackage

    $NugetPackage = New-BcNuGetPackage `
        -appfile $app `
        -packageId "{publisher}.{name}.runtime-{version}" `
        -dependencyIdTemplate "{publisher}.{name}.runtime.{id}" #-prereleaseTag 'runtime'

    Push-BcNuGetPackage -nuGetServerUrl $nugetserverurl -nuGetToken $nugetToken -bcNuGetPackage $NugetPackage
}

Pulling Runtimes:

$packageName = Get-BcNuGetPackageId -publisher 'TRASER Software GmbH' -name 'TRASER Core' -id '***' -tag 'runtime'

Download-BcNuGetPackageToFolder `
    -nuGetServerUrl $nugetserverurl `
    -nuGetToken $nugetToken `
    -packageName $packageName `
    -folder "C:\***\out" `
    -downloadDependencies allButMicrosoft

Screenshots image

freddydk commented 4 months ago

I will be working on NuGet when back from vacation

lktraser commented 4 months ago

Thanks! If I can assist somehow of give feedback just let me know. Enjoy your vacation.

kine commented 4 months ago

HI @lktraser , in between, you can try to look at function Invoke-PaketForAl function in NVRAppDevOps powershell module, which is doing what you want by using Paket CLI. It needs only your app.json and the paket.exe. You can use it during CI/CD or in VSCode to download the dependencies.

lktraser commented 4 months ago

Hi Kamil, that's very good to know. I would prefer to have everything integrated and documented within BCContianerHelper but I will look at that module to validate my work. At the moment I think I can make everything I need work I just want to make it easier for all partners and make sure they all work to the same standards.

lktraser commented 3 months ago

Hi @kine and @freddydk, I would really like to push this forward. To make this easier could you give me examples using bccontainerhelper for the following scenarios?

  1. Is a check needed before trying to push to nuget. I've used Find-BcNuGetPackage so far (see code above)
  2. Push Runtime Packages: Indirect and also direct package (add a new runtime package to an existing version, e.g. new BC Version or localization)
  3. how to check if a given version + runtime BC + runtime local already exists on a given feed

Your support is greatly appreciated as always.

lktraser commented 3 months ago

I was able to answer some of my questions rewatching your presentation but new ones have come up:

What I learned:

New problems:

My current scripts for runtime push and pull look like this: Push

$packageName = Get-BcNuGetPackageId -packageIdTemplate "{publisher}.{name}.runtime.{id}" -publisher $appJson.publisher -name $appJson.name -id $appJson.id
Write-Host $packageName

$feed, $packageId, $packageVersion = Find-BcNuGetPackage `
    -nuGetServerUrl $nugetserverurl `
    -nuGetToken $nugetToken `
    -packageName $packageName `
    -version $appJson.version `
    -select Exact

if ($packageVersion -eq $appJson.version) {
    Write-Warning "Indirect Package already exists on Nuget. Skipping. $($appJson.name + ' ' + $appJson.version)"                
}
else {
    $NugetPackage = New-BcNuGetPackage `
        -appfile $appFile `
        -isIndirectPackage `
        -packageId "{publisher}.{name}.runtime.{id}" `
        -dependencyIdTemplate "{publisher}.{name}.runtime.{id}"
    Push-BcNuGetPackage -nuGetServerUrl $nugetserverurl -nuGetToken $nugetToken -bcNuGetPackage $NugetPackage
}

$packageName = Get-BcNuGetPackageId -packageIdTemplate "{publisher}.{name}.runtime-{version}" -publisher $appJson.publisher -name $appJson.name -version $appJson.version
Write-Host $packageName     

$feed, $packageId, $packageVersion = Find-BcNuGetPackage `
    -nuGetServerUrl $nugetserverurl `
    -nuGetToken $nugetToken `
    -packageName $packageName `
    -version $targetBCVersion `
    -select Exact

if ($packageVersion -eq $targetBCVersion) {
    Write-Warning "Package already exists on Nuget. Skipping. $($appJson.name + ' ' + $appJson.version + ' ' + $targetBCVersion)"
    continue
}

$NugetPackage = New-BcNuGetPackage `
    -appfile $appFile `
    -packageId "{publisher}.{name}.runtime-{version}" `
    -dependencyIdTemplate "{publisher}.{name}.runtime.{id}" `
    -packageVersion $targetBCVersion `
    -applicationDependency $targetBCVersion
Push-BcNuGetPackage -nuGetServerUrl $nugetserverurl -nuGetToken $nugetToken -bcNuGetPackage $NugetPackage

Pull

$packageName = Get-BcNuGetPackageId `
    -publisher $publisher `
    -name $name `
    -id $id `
    -packageIdTemplate "{publisher}.{name}.runtime.{id}"

Download-BcNuGetPackageToFolder `
    -nuGetServerUrl $nuGetServerUrl `
    -nuGetToken $nuGetToken `
    -packageName $packageName `
    -appSymbolsFolder $out `
    -version $version `
    -installedPlatform $installedPlatform `
    -installedApps $installedApps `
    -select Earliest
lktraser commented 2 weeks ago

@kine @freddydk

Next issue I'm running into seems to be related to apps which do not use all 4 version places. ForNav uses mostly the first two e.g. 7.2.0.0

This results in this behavior during pull:

Exact match found for ForNAV.CustomizableReportPack.runtime.83326d6d-11f8-49fd-981a-6f266a7c8d81
- ForNAV.CustomizableReportPack.runtime.83326d6d-11f8-49fd-981a-6f266a7c8d81
PackageId: ForNAV.CustomizableReportPack.runtime.83326d6d-11f8-49fd-981a-6f266a7c8d81
1 versions found
First version is 7.2.0
Last version is 7.2.0
No package found matching version '7.2.0.0' for package id ForNAV.CustomizableReportPack.runtime.83326d6d-11f8-49fd-981a-6f266a7c8d81
No package found matching package name ForNAV.CustomizableReportPack.runtime.83326d6d-11f8-49fd-981a-6f266a7c8d81 Version 7.2.0.0
Looking for NuGet package TRASERSoftwareGmbH.TRASERDMS365Reports.runtime-2302-241000-20241031-1 version 1.0.0.0 (LatestMatching match)

I've tried to locate the issue but the nuspec file looks correct to me but it doesn't reflect on the feed correctly: Image

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>ForNAV.CustomizableReportPack.runtime-7-2-0-0</id>
        <version>7.2.0.0</version>
        <title>Customizable Report Pack</title>
        <description></description>
        <authors>ForNAV</authors>
        <dependencies>
            <dependency id="ForNAV.ForNAVLanguageModule.runtime.f94c6dff-0118-4c1d-a7d4-382033529ed3" version="7.2.0.0" />
            <dependency id="ForNAV.ForNAVCore.runtime.6f0293d3-86fc-4ff8-9632-54a580be6546" version="7.2.0.0" />
            <dependency id="Microsoft.Application" version="20.3.0.0" />
            <dependency id="Microsoft.Platform" version="1.0.0.0" />
        </dependencies>
    </metadata>
    <files>
        <file src="ForNAV_Customizable Report Pack_7.2.0.0_RUNTIME-23.0.app" target="ForNAV_Customizable Report Pack_7.2.0.0_RUNTIME-23.0.app" />
    </files>
</package>

Image

This seems to be resolvable with some additional [NuGetFeed]::NormalizeVersionStr() in FindPackageVersion. I will create a PR.