Einbetten von Build-Informationen lokal und in CI

  • C#

    Einbetten von Build-Informationen lokal und in CI

    Hallo,

    meine Frage ist kein Problem, sondern viel mehr ein "Kennt ihr da was?". Meine Anwendungen werden alle über CI/CD gebaut und auf Testsysteme ausgeliefert. Alles automatisiert über Azure DevOps. Ich möchte bei allen Komponenten die entsprechenden Buildinformationen einbetten um diese zur Laufzeit abrufen zu können. Es geht hierbei hauptsächlich um .NET Core Anwendungen, die in C# geschrieben sind. Als Buildsystem wird aktuell das standardmäßige MSBuild des .NET Core SDKs benutzt. Das Projekt sollte sowohl auf Linux als auf Windows kompilierbar sein.

    Benötigte Informationen:
    - GitCommitHash: string
    - GitCommitMessage: string
    - GitBranch: string
    - CiBuildNumber: string (nur wenn über CI gebaut und nicht auf Entwicklungsrechner)
    - IsCiBuild: bool (Das Detektieren sollte über Auslesen von Umgebungsvariablen, die nur in CI verfügbar sind, möglich sein-)

    Aktuelle Vorgehensweise:
    Es gibt eine BuildConfig.cs als Klasse in jedem Projekt á la

    C#-Quellcode

    1. public static class BuildConfig
    2. {
    3. public const string BuildNumber = "#{Build.BuildNumber}#"; // Das sind die Namen der Variablen innerhalb der CI
    4. // und die verbleibenden Infos noch...
    5. }


    Hier sind Tokens eingesetzt, die während des CI Builds durch die entsprechend angegebenen Variablen ersetzt werden. Das hat leider zur Folge, dass in den lokalen Builds beim Abfragen der Werte nur die Tokens zurückgegeben werden, da diese ja nur in der CI ersetzt werden. Es wäre cool, diese BuildConfig.cs während des Builds eines Projekts automatisch erstellen zu lassen und dass diese auch entsprechend in IntelliSense auftaucht (kein definitives Muss). Man könnte ja auch die BuildConfig.cs vordefinieren (was die Fehler in VS eingrenzen würde) und nur die Werte während des Builds (über einen MSBuild Task?) setzen. Das wäre eine bzw. zwei Möglichkeiten dieses Problem anzugehen. Habt ihr Ideen/Erfahrungen damit? Ich habe bei entsprechenden Internet-Suchen nicht viel gefunden. Ich bin lediglich über diese Frage gestolpert, dessen Lösung mir aber nicht wirklich weiterhilft, da ich nicht wirklich viel mit MSBuild Customization gearbeitet habe.

    Habe mich dann mal mit Buildsystemen im Allgemeinen auseinander gesetzt: Fake und Cake. Cake hat ein Git-Addin, wobei ich zur Codegenerierung nichts gefunden habe. Hat sich damit mal jemand auseinander gesetzt?

    So here's the thing...


    Vor kurzem habe ich eine Android App mit Java und dem Buildsystem mit Gradle programmiert. Auch dort habe ich natürlich meine Buildinformationen in der CI eingebunden. Allerdings habe ich da nach kurzer Zeit einen meiner Meinung nach besseren und eleganteren Weg gefunden. Und zwar wie in dem folgenden Ausschnitt (Die Sprache, die hier zum Einsatz kommt heißt Groovy und basiert auf Java):


    Quellcode

    1. def getGitHash = { ->
    2. def stdout = new ByteArrayOutputStream()
    3. exec {
    4. commandLine 'git', 'rev-parse', '--short', 'HEAD'
    5. standardOutput = stdout
    6. }
    7. return stdout.toString().trim().replace("\"", "\\\"")
    8. }
    9. def getGitBranch = { ->
    10. def fromEnv = System.getenv("BUILD_SOURCEBRANCH")
    11. if (fromEnv) {
    12. return fromEnv.substring("refs/heads/".length()).replace("\"", "\\\"");
    13. } else {
    14. def stdout = new ByteArrayOutputStream()
    15. exec {
    16. commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
    17. standardOutput = stdout
    18. }
    19. return stdout.toString().trim().replace("\"", "\\\"")
    20. }
    21. }
    22. def getIsCI = { ->
    23. return System.getenv("BUILD_BUILDNUMBER") != null;
    24. }
    25. # Und die anderen Funktionen, die in etwa gleich funktionieren
    26. android {
    27. # ...
    28. buildConfigField "String", "GitHash", "\"${getGitHash()}\""
    29. buildConfigField "String", "GitBranch", "\"${getGitBranch()}\""
    30. buildConfigField "String", "BuildNumber", "\"${getBuildNumber()}\""
    31. buildConfigField "String", "GitMessage", "\"${getGitCommitMessage()}\""
    32. buildConfigField "boolean", "IsCIBuild", "${getIsCI()}"
    33. # ...
    34. }


    Das Resultat ist folgender generierter Java-Code:

    Quellcode

    1. public final class BuildConfig {
    2. public static final boolean DEBUG = Boolean.parseBoolean("true");
    3. public static final String APPLICATION_ID = "xx.yy.zz";
    4. public static final String BUILD_TYPE = "debug";
    5. public static final String FLAVOR = "";
    6. public static final int VERSION_CODE = 1;
    7. public static final String VERSION_NAME = "1.0";
    8. // Fields from default config.
    9. public static final String BuildNumber = "Local Build";
    10. public static final String GitBranch = "develop";
    11. public static final String GitHash = "6c87e82";
    12. public static final String GitMessage = "Merge branch 'hotfix/login-failed' into 'develop'";
    13. public static final boolean IsCIBuild = false;
    14. }


    Das Besorgen der Informationen erfolgt somit über den Buildprozess selbst und ist nicht abhängig von Azure DevOps die entsprechenden Tokens zu ersetzten. Diese Klasse kann nach dem ersten Build (folglich generiert in einem "versteckten" Ordner) einfach genutzt werden und es kann entsprechend auf die statischen Variablen zugegriffen werden. Das Coole ist, dass die Buildinformationen jetzt auch beim lokalen Build generiert werden. Abschließend die zusammenfassende Frage: "Kennt ihr da was, um das in .NET Anwendungen umzusetzen?" :)

    Freue mich auf Antworten und Diskussionen :thumbsup:

    VG,
    Julian
    Hmkay. :|

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „jedijaeger“ ()