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