Numérotation automatique des builds Go : résoudre le problème de versionnage une fois pour toutes

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi le versionnage manuel est un calvaire pour chaque développeur Go

\n

Avez-vous déjà pensé : « Quelle version est actuellement en production ? » ou passé une heure à comprendre quel commit a causé un bug dans un binaire compilé il y a un mois ? Si oui, vous êtes au bon endroit. La question « Application auto build versioning » est l'une des plus populaires sur Stack Overflow (des milliers de vues et des dizaines de solutions). Et ce n'est pas pour rien : dans le développement moderne, où les pipelines CI/CD lancent des builds toutes les 10 minutes, l'attribution manuelle des versions est une voie vers le chaos.

\n

Dans cet article, nous allons détailler le versionnage automatique des builds en Go de A à Z. Vous apprendrez à mettre en place un système qui attribue automatiquement le numéro de version, le hash du commit, la date de build et même un indicateur de dépôt « sale ». Le code fonctionnera aussi bien en développement local que dans GitHub Actions, GitLab CI ou Jenkins.

\n\n

Le problème : qu'est-ce qui ne va pas avec le version.go manuel ?

\n

De nombreux développeurs débutants créent un fichier version.go et écrivent :

\n
package main\n\nvar Version = "1.0.0"
\n

Et cela fonctionne jusqu'au premier commit. Ensuite, ça commence :

\n
    \n
  • « J'ai oublié de mettre à jour la version avant le build »
  • \n
  • « En production, une version, dans le code, une autre »
  • \n
  • « Quel commit correspond à ce build ? »
  • \n
\n

Le problème est que la version est une métadonnée de build, pas une partie du code source. Elle doit être générée automatiquement lors de la compilation.

\n\n

La solution : ldflags, l'arme secrète de Go

\n

Le compilateur Go permet d'« injecter » des valeurs de variables lors du build via le flag -ldflags. C'est ce qu'on appelle l'auto build versioning dans sa forme classique. Nous ne stockons pas la version dans le code – nous la transmettons au compilateur.

\n\n

Étape 1 : Définir la structure de version

\n

Créons un package version avec des variables qui seront renseignées lors du build :

\n
// version/version.go\npackage version\n\nvar (\n    // Version — version sémantique (définie manuellement ou via un tag git)\n    Version = "dev"\n\n    // Commit — hash court du commit\n    Commit = "none"\n\n    // BuildTime — heure du build au format ISO 8601\n    BuildTime = "unknown"\n\n    // IsDirty — indicateur que le dépôt contient des modifications non commitées\n    IsDirty = "false"\n)\n\nfunc String() string {\n    return "v" + Version + " (commit: " + Commit + ", built: " + BuildTime + ")"\n}
\n\n

Étape 2 : Builder avec ldflags

\n

Maintenant, la partie intéressante. Au lieu de go build, nous allons utiliser un script ou un Makefile qui calcule les valeurs nécessaires et les transmet au compilateur :

\n
#!/bin/bash\n# build.sh\n\nVERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev")\nCOMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "none")\nBUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")\nIS_DIRTY=$(git diff --quiet || echo "true")\n\ngo build -ldflags="\\\n    -X 'main/version.Version=$VERSION' \\\n    -X 'main/version.Commit=$COMMIT' \\\n    -X 'main/version.BuildTime=$BUILD_TIME' \\\n    -X 'main/version.IsDirty=$IS_DIRTY'" \\\n    -o myapp .
\n

Important : Le chemin main/version.Version dépend de la structure de votre projet. Si le package version se trouve à la racine – écrivez main/version.Version. S'il est dans un répertoire séparé – github.com/votre-username/projet/version.Version.

\n\n

Étape 3 : Utiliser dans l'application

\n

Maintenant, n'importe où dans le programme, vous pouvez afficher la version :

\n
// main.go\npackage main\n\nimport (\n    "fmt"\n    "main/version"\n)\n\nfunc main() {\n    fmt.Println("App version:", version.String())\n    fmt.Println("Is dirty repo:", version.IsDirty)\n}
\n

Compilez et exécutez :

\n
$ ./build.sh\n$ ./myapp\nApp version: v1.2.3 (commit: a1b2c3d, built: 2024-03-15T10:30:00Z)\nIs dirty repo: false
\n\n

Niveau avancé : sémantique

Blogs

Book Recommendations