Bazując na swoim doświadczeniu, zespół zajmujący się Microsoft Dynamics 365 Finance and Operations przygotował kilkanaście modyfikacji (modeli) do aplikacji, które w głównej mierze dotyczą dostosowań do wymogów polskiego prawa. Niestety nasze prawo nie słynie ze stabilności, co pociąga za sobą konieczność ciągłych poprawek i prac nad narzędziami.
Po rozdystrybuowaniu modeli wśród klientów stanęliśmy przed wyzwaniem, jakim było dokładna identyfikacja wersji naszych produktów, a co za tym idzie – możliwość szybkiego udzielenia pomocy. Oczywiście najprostszym rozwiązaniem jest ręczne zarządzanie numerami modeli. Jednakże modele koegzystują w środowisku, są łączone (buildowane), a następnie testowane w różnych konfiguracjach, więc numer ostatniej poprawki w pojedynczej modyfikacji nie był wystarczający.
Potrzebna była cecha, która z jednej strony pozwoli na sprawdzenie wersji pojedynczej funkcjonalności, a z drugiej pomoże sprawdzić, czy ta wersja jest „kompatybilna” z innymi. Z artykułu dowiecie się, jak ją znalazłem.
Problem
W CC Dynamics 365 pojawił się pomysł na aktualizację wersji podczas build. Nie znalazłem gotowego narzędzia, które przed wykonaniem build zaktualizowałoby wersję w deskryptorze zapisanym w xml. Numer wersji miał posiadać numer changeseta ostatniej zmiany. Deskryptor dla D365 zapisany w formacie xml według zamierzeń ma zawierać informacje o wersji jak niżej:

Koncepcja
Ten przypadek jest wykonywany podczas build z użyciem Microsoft-Hosted Agent w Azure DevOps Pipelines. Aktualizacja wersji zostanie wykonana jako krok w pipeline przez skrypt napisany w PowerShell z wykorzystaniem Rest API. Repozytorium jest w TFVC.
Działanie skryptu

Autoryzacja
Aby zweryfikować numer changeseta ostatniej zmiany dla konkretnego modelu i zrobić checkin zmian dla pliku deskryptora, używam poleceń kontroli wersji Team Foundation z poziomu PowerShell, autoryzując się przez token OAuth. Korzystając z DevOps pipelines, należy pamiętać o wyrażeniu zgody na dostęp do OAuth token przez zmienną System.AccessToken. Dzięki takiemu rozwiązaniu autoryzacja przebiegnie bez wyświetlania okna logowania oraz podawania nazwy użytkownika i hasła.

Weryfikacja autora zmiany
Sprawdzenie autora zmiany odbywa się przez Rest API, a autoryzacja z wykorzystaniem PAT. Osobisty token dostępu powinien mieć pełne uprawnienia do odczytywania, zapisywania i zarządzania kodem oraz repozytorium.
Zadania
Pierwszym krokiem jest wygenerowanie listy modeli zawierających plik deskryptora, który ma zostać zaktualizowany. W tym przypadku sprawdziło się wylistowanie katalogów przez Get-ChildItem, wskazując ścieżkę Metadata w repozytorium.
$Solutions = @(Get-childitem Metadata)
Pętla Foreach uruchamia się dla każdego wylistowanego modelu osobno i zawiera zadania wymienione w dalszej części artykułu.
Foreach ($Solution in $Solutions) {
…
}
Ostatnią zmianę można zweryfikować komendą tf history, która po dodaniu parametru /stopafter:1 wskaże informację o ostatniej zmianie w formie tabeli. Z pomocą PowerShell należy zapisać jedynie numer changeseta do zmiennej (w tym przypadku $SolutionVersion) (po więcej informacji odsyłam do artykułu).
Kolejnym krokiem jest weryfikacja autora zmiany, aby wykluczyć zmiany wprowadzone przez użytkownika „Build Service”, który dokonuje aktualizacji deskryptora podczas uruchomienia zautomatyzowanego pipeline. Używając Rest API i polecenia GET, zostanie zwrócona informacja o autorze changseta konkretnego pliku w repozytorium. (po więcej informacji odsyłam do artykułu).
Po wskazaniu ścieżki deskryptora należy uruchomić pętlę Foreach oraz instrukcję if wykluczającą wyżej wspominanego użytkownika „Build Service” i wprowadzić zmiany w pliku xml, używając wcześniej utworzonej zmiennej z numerem changeseta. VersionBuild, VersionMajor i VersionMinor zostają zaktualizowane z użyciem Get-Date.
foreach ($DescriptorFile in $DescriptorPath) {
if ($result.author.displayName -ne "ProjectName Build Service (OrganizationName)") {
$Day = (Get-Date).day # VersionBuild
$Month = (Get-date).month # VersionMajor
$Year = (Get-Date).year # VersionMinor
$xml = New-Object XML
$xml.Load($file)
$VersionBuild = $xml.SelectSingleNode("//VersionBuild")
$VersionBuild.InnerText = $Day
$VersionMajor = $xml.SelectSingleNode("//VersionMajor")
$VersionMajor.InnerText = $Year
$VersionMinor = $xml.SelectSingleNode("//VersionMinor")
$VersionMinor.InnerText = $Month
$VersionRevision = $xml.SelectSingleNode("//VersionRevision")
$VersionRevision.InnerText = $SolutionVersion
$xml.Save($file)
}
W instrukcji else pozostają obecne wartości ostatniego changeseta, natomiast wartości zawierające datę zostają zaktualizowane.
Na końcu instrukcji if oraz else, należy użyć komendy tf checkin do zatwierdzenia zmian w deskryptorze.
tf checkin $DescriptorFile /comment:"Updated model $Solution version to $Day.$Month.$Year.$SolutionVersion in $SolutionDescriptor"
Po zatwierdzeniu zmian wersja zostaje zaktualizowana. W przypadku zmiany wykonanej przez Build Service aktualizacja numeru changseta jest pomijana.



Używając opisanego skryptu, należy pamiętać o wyłączeniu innych kroków związanych z wersjonowaniem w pipeline.

Po wdrożeniu paczki na środowisko D365 możesz sprawdzić wersję modelu, korzystając z platformy.

Zakończenie
Artykuł przedstawia moje rozwiązanie przedstawionego we wstępie problemu z dokładną identyfikacją wersji naszych produktów. Poza odświeżaniem tokenu PAT skrypt nie wymagał ode mnie jakichkolwiek działań. Skrypt, jako krok w pipeline, uruchamiany jest cyklicznie przed każdym build. Wszelkie zamierzenia zostały spełnione.
***
Jeśli interesuje Cię tematyka Dynamics 365, zajrzyj koniecznie do innych artykułów naszych autorów.
Zostaw komentarz