Jeg har i den seneste tid kigget lidt mere på hvordan man egentlig laver et setup som kan understøtte at man laver nuget pakker (eller noget andet som man står og skal verisonere og udgive). Jeg har kigget på følgende:

  1. Build
  2. Release
  3. Versionering
  4. Dookumentation

Mit udgangspunkt har været at lave en (eller flere) nuget pakker, men man kan egentlig godt overføre denne praksis til fx en applikation eller andet, som man gerne vil udgive. Bottomline: man har noget, man gerne vil udgive på regulær basis, det skal versioneres og dokumenteres.

Udgangspunkt

Jeg vil tage udgangspunkt i mit test bibliotek, LogSink, som jeg har brugt som prøveklud, til denne side. Biblioteket er i sig selv ikke noget at råbe hurra for, men hele setuppet omkring biblioteket er lavet, så man kan finde inspiration, eller blot overføre 1:1 til sit eget. Servitr.LogSink består af følgende:

  1. To nuget feeds (en beta test feed, og en stable feed)
  2. En dokumentationsside som kan forklare slutbrugeren om installering, tips og tricks og give en "getting started"
  3. Offentlig tilgængelig release pipeline
  4. Koden er open source og frit tilgængelig

Byg og release

Da jeg bruger Azure DevOps har jeg sat det hele op i en yaml fil, som kan findes her. Key take aways er:

  1. Exclude master, og byg kun master hvis master bliver tagget (tagget bruges af gitversion til at udregne versionsnummeret til nuget pakken)
  2. Brug gitversion til at udregne versionsnummeret
  3. Brug to feeds: en til beta pakker, og en til stable pakker
  4. Byg en nuget pakke pr projekt, hvis du laver .NET Core udvikling. Det er sådan toolingen virker. I "gamle" dage med .NET frameworket, kunne man via nuspec filen bygge et enkel pakke udfra flere projekter, dog er det ikke fuldt understøttet endnu i .NET Core

Overstående får du med hvis kopierer pipeline filen over i dit eget projekt. Husk blot at installere gitversion task'en fra DevOps marketplace, og du er kørende.

Jeg overvejede at bygge to versioner af biblioteket hver gang:

  1. et sæt af pakker som indeholder versionsnummeret + prereelase tag (fx 1.0.0-beta0001), og
  2. et sæt af pakker som indeholder kun versionnumeret (fx 1.0.0)

Overstående er noget som nogen gør, så man kan release det byg til ens interne beta feed, hvis det viser sig stable nok, dog har jeg valgt at man i stedet skal merge ned og tagget releaset, som så bygger igen. Normalt er jeg fan af at man bygger så få gange som muligt, men jeg kunne godt forstille mig at man

  1. laver et beta release
  2. tester, og fikser nogle bugs, hvis alt derefter er stable, så
  3. laver man dokumentationsopdatering, og en release fil

Da man nok 9/10 gange skal fikse enkelte bugs, opdatere dokumentation osv, så vil jeg hellere at man bygger det igen, i stedet for at lave scripts som kopierer filer ind i den byggede nuget pakke, ændrer versionsnumre etc. Det er ikke gennemskueligt. Læg så dertil at hvis man gerne vil lave md5 kalkulering, så skal denne også opdateres, hvis man manuelt tilføjer filer, før man releaser til ens stable feed.

Man kunne også blot bygge to versioner, som beskrevet i starten, og ikke lave noget inkluderet dokumentation, release fil etc. Men skal man fikse nogle bugs, som man næsten altid skal, så skal man alligevel bygge igen. Jeg har derfor valgt ikke at lave disse scripts, og i stedet for holde det simpelt.

Versionering

Til versionering bruger jeg GitVersion. Min konfigurationsfil bygger for det meste på default konfigurationen, og er derfor meget simpel (ja jeg har ingen konfigurationsfil, da default konfigurationen bygger på git flow). Vil man køre det hele i fx continous deployment mode, kan man have en gitversion.yml fil som ser således ud:

    assembly-versioning-scheme: MajorMinorPatch
    mode: ContinuousDeployment
    branches: {}
    ignore:
      sha: []
    merge-message-formats: {}

Jeg vil anbefale at man laver et test git repo, installere GitVersion lokalt, læser dokumentationen (læs specielt den del om de forskellige modes) og tester lidt (gitversion kan hjælpe dig igang ved at du kører gitversion init i konsollen). GitVersion kan mange ting. Man kan bumpe versioneringen via commit beskeder, kun incremente versionen på merge, tagge versionsnummeret på master osv osv osv. Alt afhængig af hvad du bygger, skal du bruge de forskellige features.  Jeg valgte forkert i starten.

Det forkerte valg

Bruger man GitVersion har jeg fundet ud af at man skal tage stilling til ens branching strategi. Vil man bruge

  1. Git flow
  2. Github flow

GitVersion understøtter begge. Jeg valgte i første omgang github flow, og jeg testede det utrolig meget (som mine releases er udtryk for på servitr.logsink). Dog indså jeg at git flow var vejen frem.

Det rigtige valg

I sidste ende valgte jeg:

  1. git flow passer perfekt til nuget pakke udvikling,
  2. brug et git tag til at styre release - formateringen af tagget, skal vore x.x.x (hvis du følger SemVer 2.0.0) og ikke =vx.x.x=som i SemVer 1.0.0. Github forstår =x.x.x=og dine commit hash vil fremgå som releases i release tabbet. Meget smart! Så kan slutbrugeren altid se fra hvad commit dit release gælder og eventuel klone ned, modificere, debugge og teste, hvis slutbrugeren oplever en fejl, eller bare gerne vil udbygge koden med noget custom funktionalitet

Kør GitVersion

For at opdatere disse ting i .NET Core kører man blot

    dotnet tool install --global GitVersion.Tool
    dotnet gitversion /updateprojectfile

Man kan nu køre en dotnet build og alt bliver korrekt sat på DLL filen

/images/dllprop.png

Her kan I se at både File version og Product version bliver sat. Man har derved endnu nemmere ved at debugge et problem hvis en slutbruger sidder med et problem, da han blot kan sende dll'en og man vil derved kunne genskabe koden til den korrekte version og/eller branch og/eller commit sha. Smart.

dotnet gitversion gør brug af ens GitVersion.yml fil.

Dette tool kan fx bruges hvis man bygger og releaser i gitlab. GitHub har en task til det (som i kan se i brug hvis i kigger her).

Dokumentation

Jeg bruger to dokumentations versioner:

  1. readme.md - målgruppen er udviklere og brugere af github
  2. en github side - som er underlagt kildekontrol. Målgruppen er brugere af nuget, som gerne vil vide hvordan man kommer igang

Readme filen indeholder links til github siden. Informationen på de to sider er ikke 1:1. De læner sig meget opad hianden. Havde jeg gjort ekstra meget ud af det, ville readme filen forklare endnu mere om hvad der skal til hvis man vil contribute til biblioteket, tekniske detaljer osv. Github siden ville indeholde en "getting started" og nogle eksempler.

Jeg vil anbefale at man forsøger at gøre overstående, så der både er noget til udvikleren, som gerne vil bidrage, og noget til udvikleren, som bare gerne vil bruge.

Jeg vil dog gerne understrege: hold det open sourcealle kan modificere, teste, debugge, indmelde issues, og GØRE DET BEDRE. Alle får noget ud af det. Alle hjælper hinanden. Det er godt og gøre verden til et bedre sted.

Mit bibliotek som inspriration

Vil du gerne selv igang, så brug:

  1. Min gitversion fil
  2. Min pipeline fil - såfremt du bruger Azure DevOps

Derved får du versionering, og hele din release pipeline. Du er hurtig igang (det eneste du skal er at sætte et library op i Azure DevOps, og et beta feed). Om du skal bruge git flow eller github flow (eller en helt tredje), en eller flere nuget pakker eller opdatere pipeline filen, så den laver to versioner (en med prerelease tag og en uden), er helt op til dig.

Du kan selvfølgelig kun bruge pipeline filen, hvis du bruger Azure DevOps. Jeg vil også anbefale dig at smide koden et sted som fx Github. Bruger du Github, så lav en github side som præsenterer brugseksempler, installationsvejledninger og hvor man kan finde mere information (fx github repo'et).

Key takeaways

  1. hold det open source
  2. lav dokumentation, gerne opdelt: en til udvikleren som vil udvide, og en til slutbrugeren, som bare gerne vil bruge
  3. brug gitversion
  4. lav to feeds: en beta feed, og en stable feed (om det er nuget feed til nuget pakker, eller en FTP download til exe filer er såvidt ligemeget)