Automatyczne zwiększanie numeru kompilacji (wersji) programu

Wpadłem dzisiaj na pomysł, że całkiem fajnie byłoby, gdyby przy każdej kompilacji projektu w Visual Studio numerek jego wersji sam się powiększał. Szukałem rozwiązania w internecie – niestety bezskutecznie. Może robiłem to zbyt niewnikliwie, jednak zamiast marnować czas na dalsze poszukiwania postanowiłem… W jakiś sposób sam rozwiązać ten problem.

Numer wersji programu, a numer kompilacji

Jak powszechnie wiadomo oprogramowanie zazwyczaj oznacza się dwoma numerami. Są to numer wersji oraz kompilacji. O ile numer wersji zmienia się zwykle tylko wtedy, kiedy wydaje się nową wersję programu, o tyle numer kompilacji jest numerem, który jak mówi sama nazwa – zmienia się podczas każdej kompilacji. Rzecz bardzo przydatna. Dzięki niej rozsyłając aplikację do testerów, możemy łatwo zidentyfikować kto, jaką wersję programu posiada i nie okaże się, że finalna wersja osiągnęła numer 100. Będziemy mieli po prostu Program v1.0 build 100.

No dobrze, ale czy Visual Studio nie pozwala na takie automatyczne zwiększanie numeru kompilacji?

Szczerze mówiąc, to nie mam pojęcia. Nie doszukałem się tego w opcjach, ale jest ich dosyć sporo, więc mogłem coś pominąć. Jeżeli coś o tym wiecie to dajcie znać w komentarzach 😉

Rozwiązanie: własna aplikacja do aktualizowania wersji i „Pre-build event command line”

Dobrze przejdźmy, więc w końcu do rzeczy. Jak ja poradziłem sobie z tym problemem? Rozwiązałem go, pisząc osobną aplikację, która podmienia klasę z numerem kompilacji i wywołuję ją zawsze przed kompilacją programu. Jak wygląda kod owej aplikacji? Jest naprawdę bardzo prosty:

Prosty i… dosyć prymitywny. Jednak słyszałem, że najprostsze rozwiązania są najlepsze 😉 W miarę potrzeby można go zawsze ulepszyć/zmodyfikować. Jak konkretnie działa? Po prostu podmienia plik z klasą przechowującą numer kompilacji we wskazanym projekcie, na taki sam, z tą różnicą, że zmieni zwracany przez nią numer na aktualną datę. Tadam! Mamy nasz numer kompilacji, który w istocie jest jej datą!

Programik można spokojnie skompilować i wrzucić do lokalizacji, która w swojej ścieżce nie zawiera spacji. To bardzo ważne, bo jeżeli będzie inaczej, to wystąpią problemy z jego uruchomieniem.

Jak tego używać?

Wszystko skompilowane? Program znajduje się w jakiejś dobrej lokalizacji? (np. na dysku c). Jeżeli tak to przejdźmy dalej.

W celu przetestowania tego rozwiązania należy stworzyć nową aplikację WPF i dodać do niej klasę o nazwie np. Build.

2

Kolejną rzeczą do zrobienia jest wyświetlenie wersji kompilacji w naszym oknie głównym aplikacji. W tym celu należy dodać w kodzie xaml, taką oto linijkę:

3

Odczytuje ona wartość właściwości z klasy Build o nazwie _Build, która jeszcze nie istnieje, bo jej nie utworzyliśmy. Właściwie nie musimy, bo zostanie utworzona automatycznie. Oczywiście równie dobrze, możemy tą wartość odczytywać bezpośrednio w C#.

Następnie przejdźmy do ustawień projektu, zakładka „Build Events”. W pierwszym polu wpisujemy coś takiego:

4

Powyższa linijka uruchomi wcześniej napisaną aplikację, znajdującą się na dysku C, zawsze przed kompilacją projektu. Argumentami dla aplikacji są kolejno: nazwa namespace’a, jakiego używamy w projekcie (moja to testapp), oraz lokalizacja pliku Build.cs. Będzie on zawsze nadpisywany, więc nie należy tutaj umieszczać żadnego dodatkowego kodu. Należy pamiętać, aby również ścieżka do projektu nie zawierała spacji – inaczej program otrzyma błędną ścieżkę. Jeżeli jednak spacje są obecne i nic nie da się z tym zrobić to umieszczenie drugiego argumentu w cudzysłów powinno rozwiązać problem.

Jaki jest efekt po kompilacji? Oto i on:

a

Program nadpisał plik Build.cs przed kompilacją i tym samym możemy wyświetlić jego zawartość – czyli nasz (dosyć) unikalny numer.

Cóż to chyba na tyle, dajcie znać co o tym sądzicie w komentarzach 😉

816 total views, 2 views today

10 przemyśleń nt. „Automatyczne zwiększanie numeru kompilacji (wersji) programu

  1. Nie wystarczy zrobić tak: [assembly: AssemblyVersion(„1.0.0.*”)] w AssemblyInfo ?

  2. Ok, nie ogarniam Twojego toku myślenia, że ten pomysł jest prosty i dobry.
    Po co zwracać statyczny tekst generowany przez zewnętrzną aplikację (która i tak jest uruchamiana przy każdej kompilacji) skoro możesz od razu zrobić plik build.cs który wygląda tak:

    Nie musisz nic dopisywać w Build Events, nie jesteś zależny od zewnętrznej aplikacji (która może zmienić lokalizację itd.). Zastosowanie tego jest banalne w kolejnych aplikacjach (zmieniasz tylko namespace).

    Druga sprawa to użycie w pliku AssemblyInfo.cs takiego kodu (zamiast obu linijek które są tam domyślnie na końcu):

    Zamiast gwiazdki kompilator podstawia do revision ilość sekund od północy lokalnego czasu podzieloną przez 2 (np. 1.0.0.18589).

    Zamiast gwiazdki kompilator wstawi do build liczbę dni od któregoś roku (nie pamiętam dokładnie skąd to się brało) a do revision to co wyżej (np. 1.0.6155.18589).

    • Co do przykładu pierwszego. Kod return DateTime.Now.ToString(„MMddyyHHmm”); będzie zwracał aktualną datę na komputerze, na którym uruchomiono aplikację. Okaże się więc, że build dynamicznie zmienia się na komputerze użytkownika 😉

      Co do [assembly: AssemblyVersion(„1.0.0.*”)], kurcze nie wiem dlaczego u mnie nie działa, wstawiam to kompiluję, wchodzę we właściwości pliku (exe) i stoi 1.0.0.0… Jak będę miał chwilę czasu to „ogarnę”.

      Pozdrawiam 😉

  3. Tak w ramach podsumowania.
    Gwiazdki mogą się pojawić tylko w AssemblyVersion. Do tego z wartości jakie zostaną tam wstawione można wyliczyć datę kompilacji (http://stackoverflow.com/questions/1766990/can-i-translate-net-assembly-versions-to-dates). Natomiast nie jest to zalecane. Od taki „ficzer” kompilacji bez poparcia w standardzie .NET.
    Do dyspozycji jest jeszcze wersja pliku AssemblyFileVersion i wersja produktu jako całości AssemblyInformationalVersion. Tutaj jest całkiem przystępnie opisane co jest czym i jak to się je (http://stackoverflow.com/questions/64602/what-are-differences-between-assemblyversion-assemblyfileversion-and-assemblyin).
    Warto też przypomnieć o ograniczeniach AssemblyInfo i AssemblyFileVersion. Oba przypadki pracują na formacie #.#.#.# gdzie pojedyncza wartość jest z zakresu [0,65535). Ograniczenie bierze się z obsługi wersji po stronie samego systemu operacyjnego. Tzn 4 wartości zapisane są w 2xDWORD. Czyli mamy 4x16bit. Przy przekroczeniu wartości w AssemblyInfo projekt w ogóle się nie skompiluje, a przy AssemblyFileVersion licznik się przekręci. Zaszłość taka. Stąd kuszące używanie formatów zależnych od daty nie jest możliwe wprost. Wartości się po prostu nie zmieszczą.
    Dodam jeszcze jak to robię w pracy. Korzystamy z SVN+TortoiseSVN. Cykl wydawania wersji aplikacji / biblioteki jest taki, że podnoszę ręcznie numer wersji AssemblyInfo i AssemblyFileVersion w pliku dodatkowym nie kompilowanym pliku AssemblyInfo.template.cs i wykonuję commit. Jego rewizja jest tym znacznikiem charakterystycznym i odniesieniem w historię projektu który mnie interesuje kiedy ktoś wykonuje testy / zgłasza błąd. Dopiero teraz mając za sobą stworzenia rewizji mogę skompilować projekt i wydać faktyczną wersję. W czasie kompilację w Pre-build event wywoływane jest narzędzie SubWCRev które podmienia pewne słowa kluczowe z AssemblyInfo.template.cs generując nowy AssemblyInfo.cs z numerem rewizji SVN zaszytej w wersji aplikacji. O przekroczenie 65535 rewizji raczej się nie boję. Z reguły oscylują koło max kilku tysięcy przy największych projektach. Do 65tys jeszcze bardzo daleko droga i obawiam się, że nie za mojego życia 😉

Możliwość komentowania jest wyłączona.