Najlepsze praktyki / wskazówki dotyczące utrzymywania numerów wersji zestawu


154

Szukam wskazówek, sugestii, a nawet dyktowania, jak zarządzać trzema różnymi numerami wersji zestawu dla zestawu .NET. Wersja produktu jest najprostsza, ponieważ normalnie wydaje się, że jest to podyktowane biznesem. Następnie wydaje się, że wersja pliku służy do przechowywania wersji między wdrożeniami, gdzie rzeczywista wersja zestawu jest używana tylko podczas wysyłania.

W tej chwili szukam prostego sposobu etykietowania wersji testowych i konserwacyjnych zespołu, od którego żaden nie jest zależny, więc patrzę na automatyczne zwiększanie numerów kompilacji i rewizji w wersji pliku, a dla ostatecznego wydania, kopiowanie bieżącej wersja pliku do wersji zestawu. Produkt jest w użyciu produkcyjnym, ale wciąż jest w fazie rozwoju - wiesz - jedna z tych małych firm, w których brak zmian w infrastrukturze kontroli.


Odpowiedzi:


211

Wersjonowanie jest czymś, co bardzo mnie interesuje i spędziłem dużo czasu próbując wymyślić łatwy w użyciu system wersjonowania. Z tego, co już powiedziałeś w swoim pytaniu, jasno wynika, że ​​zrozumiałeś jeden ważny punkt, numery wersji zestawu nie są synonimami wersji produktu. Jeden jest napędzany technicznie, a drugi przez biznes.

Poniższe założenie zakłada, że ​​używasz jakiejś formy kontroli źródła i serwera kompilacji. W kontekście używamy TeamCity i Subversion / Git. TeamCity jest darmowy dla niewielkiej (10) liczby projektów i jest bardzo dobrym serwerem do kompilacji, ale są też inne, z których niektóre są całkowicie bezpłatne.

Co oznacza numer wersji

To, co dla jednej osoby oznacza wersja, może oznaczać coś innego dla drugiej, ogólna struktura jest duża, drobna, makro, mikro. Sposób, w jaki patrzę na numer wersji, polega na rozbiciu go na dwie części. Pierwsza połowa zawiera opis wersji głównej (Major) i wszelkich kluczowych aktualizacji (Minor). Druga połowa wskazuje, kiedy został zbudowany i jaka była wersja kodu źródłowego. Numery wersji oznaczają również różne rzeczy w zależności od kontekstu, czy jest to interfejs API, aplikacja internetowa itp.

Major. Minor. Build.Revision

  • Revision Jest to liczba pobrana z kontroli źródła w celu zidentyfikowania tego, co faktycznie zostało zbudowane.
  • BuildJest to stale rosnąca liczba, której można użyć do znalezienia konkretnej kompilacji na serwerze kompilacji. Jest to ważna liczba, ponieważ serwer kompilacji mógł dwukrotnie zbudować to samo źródło z innym zestawem parametrów. Użycie numeru kompilacji w połączeniu z numerem źródłowym pozwala zidentyfikować, co i jak zostało zbudowane.
  • MinorPowinno się to zmienić tylko wtedy, gdy nastąpi znacząca zmiana w interfejsie publicznym. Na przykład, jeśli jest to interfejs API, czy konsumujący kod nadal będzie mógł się kompilować? Ta liczba powinna zostać zresetowana do zera, gdy zmieni się liczba główna.
  • Majorwskazuje, z jakiej wersji produktu korzystasz. Na przykład główny ze wszystkich zespołów VisualStudio 2008 to 9, a VisualStudio 2010 to 10.

Wyjątek od reguły

Zawsze są wyjątki od reguły i będziesz musiał się dostosować, gdy się z nimi spotkasz. Moje oryginalne podejście opierało się na używaniu subversion, ale ostatnio przeniosłem się na Git. Kontrola źródła, taka jak subversion i sejf źródłowy, które używają centralnego repozytorium, mają numer, który można wykorzystać do zidentyfikowania określonego zestawu źródeł z danego czasu. Nie dotyczy to rozproszonej kontroli źródła, takiej jak Git. Ponieważ Git korzysta z repozytoriów rozproszonych, które znajdują się na każdej maszynie deweloperskiej, nie ma automatycznego zwiększania liczby, której można by użyć, istnieje hack, który wykorzystuje liczbę wejść, ale jest brzydki. Z tego powodu musiałem ewoluować moje podejście.

Major. Minor. Macro.Build

Numer wersji zniknął, kompilacja została przeniesiona do miejsca, w którym była wersja, a makro zostało wstawione. Możesz używać makra tak, jak chcesz, ale przez większość czasu zostawiam je w spokoju. Ponieważ używamy TeamCity, informacje utracone z numeru wersji można znaleźć w kompilacji, oznacza to, że jest to proces dwuetapowy, ale nic nie straciliśmy i jest to akceptowalny kompromis.

Co ustawić

Pierwszą rzeczą do zrozumienia jest to, że wersja zestawu, wersja pliku i wersja produktu nie muszą być zgodne. Nie jestem zwolennikiem posiadania różnych zestawów liczb, ale znacznie ułatwia to życie przy wprowadzaniu niewielkich zmian w zestawie, które nie mają wpływu na żadne interfejsy publiczne, a nie jesteś zmuszony do ponownej kompilacji zestawów zależnych. Sposób, w jaki sobie z tym radzę, polega na ustawianiu tylko głównych i drugorzędnych liczb w wersji zestawu, ale ustawieniu wszystkich wartości w wersji pliku. Na przykład:

  • 1.2.0.0 (AssemblyVersion)
  • 1.2.3.4 (FileVersion)

Daje to możliwość wdrażania poprawek, które nie zepsują istniejącego kodu, ponieważ wersje zestawu nie są zgodne, ale pozwalają zobaczyć wersję / kompilację zespołu, patrząc na numer wersji pliku. Jest to typowe podejście i można je zobaczyć w niektórych zespołach typu open source, patrząc na szczegóły zespołu.

Ty, jako lider zespołu, będziesz musiał być odpowiedzialny za zwiększenie mniejszej liczby, gdy wymagana jest znacząca zmiana. Jednym ze sposobów wprowadzenia wymaganej zmiany w interfejsie, ale nie złamania poprzedniego kodu, jest oznaczenie bieżącego jako przestarzałego i utworzenie nowego interfejsu. Oznacza to, że istniejący kod jest ostrzegany, że metoda jest przestarzała i może zostać usunięta w dowolnym momencie, ale nie wymaga natychmiastowego przerywania wszystkiego. Następnie możesz usunąć przestarzałą metodę, gdy wszystko zostanie przeniesione.

Jak to połączyć

Możesz zrobić to wszystko ręcznie, ale byłoby to bardzo czasochłonne, poniżej opisano, jak zautomatyzować ten proces. Każdy krok można uruchomić.

  • Usuń atrybuty AssemblyVersioni AssemblyFileVersionze wszystkich plików projektu AssemblyInfo.cs.
  • Utwórz wspólny plik informacji o zespole (nazwij go VersionInfo.cs) i dodaj go jako element połączony do wszystkich projektów.
  • Dodaj atrybuty AssemblyVersioni AssemblyFileVersiondo wersji z wartościami „0.0.0.0”.
  • Utwórz projekt MsBuild, który tworzy plik rozwiązania.
  • Dodaj zadanie przed kompilacją, która aktualizuje plik VersionInfo.cs. Istnieje wiele bibliotek MsBuild typu open source, które zawierają zadanie AssemblyInfo, które może ustawić numer wersji. Po prostu ustaw dowolną liczbę i przetestuj.
  • Dodaj grupę właściwości zawierającą właściwość dla każdego segmentu numeru kompilacji. Tutaj ustawiasz dur i moll. Numer wersji i kompilacji należy przekazać jako argumenty.

Z subversion:

<PropertyGroup>
    <Version-Major>0</Version-Major>
    <Version-Minor>0</Version-Minor>
    <Version-Build Condition=" '$(build_number)' == '' ">0</Version-Build>
    <Version-Build Condition=" '$(build_number)' != '' ">$(build_number)</Version-Build>
    <Version-Revision Condition=" '$(revision_number)' == '' ">0</Version-Revision>
    <Version-Revision Condition=" '$(revision_number)' != '' ">$(revision_number)</Version-Revision>
</PropertyGroup>

Mam nadzieję, że wyraziłem się jasno, ale jest dużo w tym zaangażowany. Prosimy o zadawanie pytań. Wykorzystam wszelkie opinie, aby stworzyć bardziej zwięzły post na blogu.


Czy rozważałeś użycie tagów wersji z GitHub? Jestem bardzo ciekawy, jak to pasuje do układanki.
raRaRa

1
@raRaRa - To jest dość stary post. Chociaż przez większość czasu nadal stoję, są rzeczy, które zrobiłbym inaczej. Przechowywanie wersji NuGet zmieniło sposób wykonywania czynności i używam tagów Git do pomyślnych kompilacji, ale na koniec dnia numer wersji w zestawie powinien wiązać się z wersją kompilacji na serwerze kompilacji i wersją tagu w kontroli źródła.
Bronumski

57

[AssemblyVersion] to bardzo ważna sprawa w .NET. Jedną z filozofii, do której zachęca firma Microsoft, jest umożliwienie jej automatycznej inkrementacji, zmuszając wszystkie projekty zależne od zestawu do ponownej kompilacji. Działa dobrze, jeśli używasz serwera kompilacji. To nigdy nie jest złe , ale uważaj na ludzi noszących miecze.

Drugim, ściślej związanym z jego rzeczywistym znaczeniem, jest to, że numer jest reprezentatywny dla wersjonowania publicznego interfejsu zestawu. Innymi słowy, zmieniasz go tylko wtedy, gdy zmieniasz publiczny interfejs lub klasę. Ponieważ tylko taka zmiana wymaga ponownej kompilacji klientów zestawu. Należy to jednak zrobić ręcznie, system kompilacji nie jest wystarczająco inteligentny, aby automatycznie wykryć taką zmianę.

Możesz dodatkowo rozszerzyć to podejście, zwiększając wersję tylko wtedy, gdy zestaw został wdrożony na komputerach poza Twoim zasięgiem. Jest to podejście stosowane przez firmę Microsoft, numery wersji zestawów .NET bardzo rzadko się zmieniają. Przede wszystkim z powodu bardzo dużego bólu, jaki powoduje u swoich klientów.

Więc to, co głosi Microsoft, nie jest tym, co praktykuje. Jego proces kompilacji i kontrola wersji są jednak niezrównane, mają nawet dedykowanego inżyniera oprogramowania, który monitoruje proces. Nie wyszło tak dobrze, szczególnie przeciążenie WaitHandle.WaitOne (int) powodowało spory ból . Naprawiono w .NET 4.0 z zupełnie innym podejściem, ale to wykracza nieco poza zakres.

To raczej zależy od Ciebie i Twojej pewności, jak dobrze możesz kontrolować proces kompilacji i cykle wydawania, aby dokonać własnego wyboru. Poza tym automatyczne zwiększanie wartości [AssemblyFileVersion] jest bardzo odpowiednie. Jednak z niedogodnością, że nie jest to obsługiwane.


11

Możesz użyć części kompilacji numeru wersji do automatycznego zwiększania.

[assembly: AssemblyVersion("1.0.*")]

W twoim środowisku wersja testowa to wersja z wersją kompilacji! = 0. W wydaniu zwiększasz część podrzędną i ustawiasz część kompilacji na 0, w ten sposób identyfikujesz zwolnione zestawy.

Jeśli zainstalujesz swoje zespoły w GAC, twój GAC zostanie zalany wieloma różnymi wersjami z czasem, więc miej to na uwadze. Ale jeśli używasz bibliotek dll tylko lokalnie, myślę, że jest to dobra praktyka.


Podoba mi się numer kompilacji 0 dla wersji wydania.
ProfK

1
Oczywiście oznacza to, że silna nazwa twojego zestawu będzie się zmieniać z każdą kompilacją, czy tego chcesz, czy nie.
Richard

9

Dodając do odpowiedzi Bronumskich , chciałbym zwrócić uwagę, że po standardzie Semantic Versioning 2.0 na semver.org ,Major.Minor.Build.Revision byłoby niezgodne z prawem ze względu na zasadę, że po zwiększeniu liczby, wszystkie regularne wartości po prawej stronie musiałaby być wyzerowany.

Lepszym sposobem przestrzegania standardu byłoby użycie Major.Minor+Build.Revision. To oczywiście nie jest do użytku w AssemblyVersionAttribute, ale zamiast tego można użyć niestandardowego atrybutu lub klasy statycznej.

Semver w TeamCity powinien być dostępny przy użyciu pakietu Meta-runner Power Pack. W przypadku git z git-flow (szczególnie w świecie .NET) pomocnym okazała się GitVersion .


2
Ciekawe, sprawdzę to. Wspomniany format numeru wersji może być użyty w atrybucie AssemblyInformationalVersion.
Bronumski

1

Nie ma sztywnej i szybkiej reguły, jeśli chodzi o wersjonowanie zestawów, więc nie krępuj się wypróbować tego, co kiedykolwiek zadziała dla Ciebie, ale sugeruję użycie podejścia 4-częściowego, ponieważ będziesz mieć elastyczność w przypadku, gdy chcesz wprowadzić pewne zmiany w przyszłości.

... na przykład: 1.0.0. *

Zastrzeżone - dodaje to dodatkowej elastyczności, na wypadek gdybyś chciał dokonać jakiejkolwiek zmiany w przyszłości. Ale domyślnie zachowaj wartość 0.

Rozważ także podpisanie zestawu silnym kluczem. Spowoduje to rozwiązanie problemu konfliktu zestawu w przypadku, gdy masz wiele wersji zestawu zarejestrowanych w GAC. MSDN Link

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.