Recently, I got the question on how to get a dependency tree from a bunch of Microsoft Dynamics 365 Business Central apps. In other words – how do I know in which order I have to import my apps to respect the dependencies.
Well, I didn’t have a ready-made script available. I only had a script my colleague provided me – so I took that as a starting point, and spent an evening in trying to put something together – as it IS a very interesting question ;-).
To be honest, we don’t need this in our company in our build pipeline, nor in our release pipeline. Nevertheless – I have heard the question multiple times, so Let’s .. Get .. Started .. ;-).
It’s obvious we will use PowerShell for this, as that’s what you will use to publish apps in an environment. You use it in build pipelines, in release pipelines, and even when you would just import in a one-off sandbox.
In PowerShell, we also have the CmdLets that Microsoft provides to manage our environment.
So .. Let’s start by linking the script, which you can find on my GitHub here: https://github.com/waldo1001/Cloud.Ready.Software.PowerShell/blob/master/PSScripts/NAV%20Extensions%20v2/GetDependencies.ps1
(I’m just providing a link, as when the script would change, you would alway see the up-to-date version of the script).
Some brief explanation
The script assumes you have a bunch of app-files somewhere. In this case, on the “c:\programData\NavContainerHelper” folder, because I’m using docker in order to run Business Central PowerShell CmdLets. You see I’m using the “Get-NAVAppInfo” cmdlet to get information about my apps. This information includes dependencies – which I will obviously need for my script. I then create my own collection of apps in PowerShell to be able to loop and do my thing.
The function AddToDependencyTree is a recursive function (wow – I didn’t use recursive functions for ages :-/) where all the “magic” happens. By looping the apps in my collection, I will always respect the dependencies by recursively drilling down into the dependency tree, and handle the lower-leveled apps by adding (or modifying) them with a lower “order” in the result-array (the DependencyArray variable).. . When completely looped, I have a new array including a decent “ProcessOrder” property in my collection.
On the bottom of the script, you see the actual loop, where I loop all the apps, and add them to the dependency tree.
To make it somewhat easier for me, and to simulate a somewhat complex dependency tree, I created this script:
It would replace the “Get-NAVAppInfo” looping through files, as it will build a “$AllApps” variable to be able to loop through. Just a tip ;-).
I did briefly look online if I could find any blogpost that already handled it – but only briefly. If I missed a solution (which is probably better than this one) – I apologize. There are so many contributors lately, it’s hard to keep track, catch up, … you know what I mean ;-). So, if you have a better (or worse ;-)) solution, don’t hesitate to mention that in the comment section.
I think you accidentally linked to the same script twice.
I believe the link to the “Test” script should be the following
Thanks for mentioning! I updated the article :-).
Could you explain why you don’t need it in your company? Do you have a monolith app or another solution to the problem?
Well, we have a repository per app, having its own build pipeline.
For apps with dependencies, we set up the download of the latest artifact, to get the symbols for compiling.
for apps that has other apps depending, we set up a trigger to start building the app that depends on “me”.
It works like a charm, and in my opinion, it’s actually better then having all these “hard” dependencies: I shouldn’t fail a build of app A, just because I broke B by changing A. May be I shouldn’t release A and B to my environment when B is broken, but I should be able to release A to another that doensn’t have B.
Breaking a dependency is a problem for the app that depends on the other, not for the one that is independent. Just Microsoft’s BaseApp in account – same reasoning.
It’s how we want to handle dependencies (or “independencies” if you will ;-)). Meaning: I won’t compile, import, all apps at the same time. They are all part of a release pipeline, which handles it without needing the dependency tree.. .
That’s at least my opinion of today .. might change in the future ;-).
And .. we definitely have no Monolith – far from it ;-). One product was divided in 11 apps ;-).
Thanks for sharing!
We using something similar in our company (inhouse – around 20 different apps per database installed).
I want to give you an example how we use it.
When ever you push something to master repo it will write in a config file which app have to be installed on the next deployment.
In this week we editing 5 apps which we have to deploy soon – some of them depends each other, some not.
Now you want to make sure that the apps are published -> installed -> unpublish old version in the right sequence.
Such a script is amazing 🙂
It was decreasing our deployment time by around 90%.
Makes sense, thanks!
There are multiple ways for same like:
Get-NavContainerAppInfo from navcontainerhelper have now new parameter -Sort and will return the dependencies
Get-ALAppOrder from NVRAppDevOps which works with container and app.json or .app files
Didn’t know that, thanks!
Isn’t it limited though to one appfile? Or does it handle multiple files, and take the entire dependency tree into account?
No, my Get-ALAppOrder use all, if you have structure like (we have);
Dependencies (git submodule)
It will take all app.json and calculate the order. If you have folder of .app files, it will take them, download missing apps from container if they are there (Microsoft apps), download missing apps from another source (we are using nuget Azure DevOps Artifact server), and calculate the order.
Ok, one evening down the drain 😉
Sorry, spaces removed…
Dependencies (git submodule)
–Dependencies (git submodule)
–Dependencies (git submodule)
Very nice solution for publishing, but you have to know in which order you have to compile your apps first 😉
Well, not in my book ;-). Every app has its own build process, its own compilation. I have no need to compile multiple apps at the same time, just download the artifact from the right repository …
@patrick, One of the approach is –
we can publish the app one by one based on the dependency matrix.
if App B & C is dependant on App A, we can deploy App A first and then B & C (separate or together).
I am running this function against an Array of Get-NAVAppInfo’s I collected from a remote server/container. It doesn’t seem to work and I suspect it has something to do with the Invoke-command that is “flattening” the resulting array, hence the subset of dependencies. Any experiences yourself in this approach?
Can you check if the dependency-information is in there? Would be good to be able to play around with it to investigate…
If we have app XXXX is dependant on YYYY.
We deployed v1.0.3 version of XXXX and then deploy v 1.0.8 version of YYYY using ALOps Extension API task (basic Auth)
is there any way to unpublish v1.0.3 of XXXX only, then deploy v1.0.2 version of XXXX.
Will the app XXXX and YYYY work as expected.
Thanks in advance
afaik, there is no way to go back a version – upgrading is not a problem.
Waldo, yes that’s grand with not going back to old version.
Can I check two things based on the deployment failure we had last week,
1. Below is the snippet of the deployment.
we had 126.96.36.199 version of XXXX deployed in release 1 using ALOps Extension API task (basic Auth)
and then in release 2, we again deploy v 188.8.131.52 version of XXXX using ALOps Extension API task (basic Auth) which one of the component deployment as part of the release 2 and we end up with Operation Failed.
2020-07-31T15:47:00.7689622Z name publisher appVersion operationType schedule status startedOn
2020-07-31T15:47:00.7702650Z —- ——— ———- ————- ——– —— ———
2020-07-31T15:47:00.7710617Z AAAA BBBB 184.108.40.206 Upload Immediate Completed 2020-07-31T15:44:10.643Z
2020-07-31T15:47:00.7719780Z YYYY BBBB 220.127.116.11 Upload Immediate Failed 2020-07-31T15:31:54.49Z
2020-07-31T15:47:00.7727723Z ZZZZ BBBB 18.104.22.168 Upload Immediate Completed 2020-07-31T15:45:36.377Z
2020-07-31T15:47:00.7736382Z XXXX BBBB 22.214.171.124 Upload Immediate Failed 2020-07-31T15:47:00.47Z
is there a way to mitigate this scenario.
2. In ALOps Extension API task (basic Auth), is there an option to check whether version 126.96.36.199 version of XXXX is already deployed and hence no need to deploy it again in release 2.
Thanks in advance.
Error details for Operation Failed. A different .app file with the same App ID (b0a7c46a-77a3-4385-a34f-4ea80173e378) and version (188.8.131.52) has already been uploaded to an environment in our service. Please verify that the App ID assigned to this extension is the correct one, increment the version number to one that has not been used, and redeploy the package. Read more here https://go.microsoft.com/fwlink/?linkid=2128807 .