W firmie od dłuższego czasu przymierzałem się do wdrożenia pewnego niewielkiego i w sumie tylko na wewnętrzny użytek – narzędzia do zautomatyzowania procesu wdrażania paczek u klientów. To co zautomatyzowane było do tej pory przeze mnie – to kompresowanie całego projektu do 7z, kopiowanie na serwer ftp, ściąganie paczki u klienta, rozpakowanie, podmiana oraz wykonanie backupu bazy. Wszystko wykonywane jako skrypt, a nie program (notabene właśnie po to z założenia są skrypty).

ASP.NET Logo

Po drodze – przy próbach stworzenia takiego narzędzia – pojawiły się 2 zasadnicze problemy wynikające z ograniczeń platformy (tu mowa przede wszystkim o Powershell oraz MSBuild). I o nich jest właśnie dzisiejszy wpis.

Problem 1

Podłączanie się przy pomocy skryptu do serwera klienckiego i wykonywanie na nim poleceń zdalnych. Jest to całkiem istotne, bo z założenia chcielibyśmy tylko uruchomić skrypt i poczekać na jego wykonanie, a nie podłączać się jeszcze przez Remote Desktop na docelową maszynę i na niej odpalać kolejny skrypt. Cóż… tak niestety zostało póki co i raczej nie wygląda by miało się to zmienić. Powershell i jego “remoting features” są zdecydowanie bardziej ograniczone i do tego stopnia nieużyteczne (w szczególności w przypadku różnorodności systemów klienckich, z którymi miałaby całość współpracować, jak i ze specyfiki sieci), że całkiem intensywnie zastanawiam się nad zainstalowaniem u klientów OpenSSH i używania ssh w tym celu. Jedyne co mnie przed tym powstrzymuje to brak uprawnień do tego typu operacji, ale to ograniczenie – jak każde - da się ominąć ;]

Problem 2, o którym jest ten wpis

Generalnie, to co było do tej pory dość uciążliwe to włączanie Visual Studio po to tylko by przebudować wszystkie projekty do najnowszej wersji oraz zrobić Publish na docelowym projekcie, a po zakończeniu uruchomić skrypt, który zajmuje się resztą. Prawda, że bez sensu?

Zastąpienie części kroków nie jest problemem. Pobranie najnowszej wersji z Mercuriala oraz przekompilowanie wszystkim projektów – to odpowiednio 1-2 linijki. Za to gorzej sytuacja ma się z Publish.

Początkowo uparcie chciałem użyć w tym celu narzędzia MSBuild, które do tego między innymi służy (jest wykorzystywane przez Visual Studio do tworzenia paczek), a to niestety jest – w przypadku tej konkretnej funkcjonalności – mocno toporne. Wymaga to specjalnego pliku xml do tego konkretnego celu budowy, który zawiera wylistowane wszystkie pliki, które mają zostać uwzględnione przy tworzeniu paczki. Dla nas jest to bardzo mało interesująca opcja; łatwiej byłoby wykonać plik xml zgodny z MSBuild Community Tasks Project, który niejako rozszerza możliwości MSBuilda. W dalszym jednak ciągu nie jest to satysfakcjonujące rozwiązanie…

Okazuje się, że wbrew pozorom kwestia Publish jest tak na prawdę trywialna, ale tylko jeśli nie będziemy używać w tym celu narzędzia jakim jest MSBuild. Wystarczy bowiem skompilować nasz projekt webowy (i wszystkie zależności) a potem skopiować w miejsce docelowe wszystkie wymagane pliki (można teoretycznie wszystkie, ale jeśli nam zależy na wielkości paczki, to będziemy chcieli znaleźć optymalną, czyli minimalną ilość plików do skopiowania).

Wiedząc już tyle należałoby teraz wskazać sposób na skopiowanie struktury katalogów i plików, która uwzględniać będzie filtry tego co ma być kopiowane, a tego co nie. Okazuje się, że jest bardzo proste i potężne narzędzie do tego, a które jest standardowo wbudowane w Powershella (sic!). Mowa o robocopy. Przykładowe użycie, które w pełni zrealizuje oczekiwaną przez nas funkcjonalność publikowania wygląda mniej więcej tak:

robocopy $source $destination *.aspx *.ascx *.dll *.config *.ashx *.asmx *.txt *.asax *.css *.xap *.js *.jpg *.jpeg *.gif *.png *.htm *.ico /s /xd obj Bin/bin Bin/"Debug All" /NS /NC/ NFL /NDL  

Pokazujemy w tym przypadku jakie rozszerzenia plików mają się znaleźć w docelowym katalogu oraz dodatkowe ustawienia, tj.:

/xdWyklucza konkretne katalogi z kopiowania
/sKopiuj podfoldery (ale z wyłączeniem pustych)
/NSNie listuj rozmiarów plików
/NCNie listuj typów plików
/NFLNie listuj nazw plików
/NDLNie listuj katalogów
Ta jedna linijka (długa co prawda, ale 1 linijka) pozwala nam w sprawny, szybki i bezawaryjny sposób przygotować pliki do paczki publikacyjnej.

A dla zainteresowanych, poniżej lista kroków do tego by przygotować całą paczkę gotową do wdrożenia u klienta:

  1. Usunięcie poprzedniego folderu publish
  2. Pobranie najnowszej wersji z repozytorium
  3. Skompilowanie wszystkich projektów (z targetem release)
  4. Wykonanie naszego kopiowania
  5. Wywalenie web.config z katalogu publikacyjnego
  6. Skompresowanie wszystkiego (tu szczególnie polecam format archiwum 7z)
  7. Wgranie na serwer

HaoZip

W ten oto piękny sposób cały proces mamy zautomatyzowany! :) Przy okazji pozwolę sobie polecić niezły programik, który może się także nieźle przydać odnośnie procesu kompresji z poziomu linii komend. Jakiś czas temu znalazłem perełkę o niepozornej nazwie: HaoZip. Nie dość, że wygląda bardzo dobrze, to do tego jest niesamowicie funkcjonalny, lekki, przejrzysty, szybki oraz darmowy. Ponadto udostępnia także interfejs osiągalny z wiersza polecenia.

Przykładowa komenda w HaoZip, która spowoduje skompresowanie całego katalogu:

C:\Program Files\HaoZip\HaoZipC.exe a -r arch.7z publishDir\*

Flaga r oznacza rekursywne załączanie podkatalogów, a flaga a oznacza dodawanie plików.

Prawda, że proste? :)

Okazuje się, że nic na siłę. W szczególności jeśli chodzi o stosowanie na siłę narzędzi, które w pierwszej kolejności przychodzą na myśl jako niezbędne do wyznaczonego zadania ;)