Gomplate est un utilitaire en Go qui permet de faire un rendu dynamique.

La possiblité d'utiliser du templating Go, d'utiliser les fonctions built-in de gotemplate et le support de datasources par Gomplate me paraissait intéressant.

Objectifs

Ce test va probablement détourner un peu l'objectif initial du produit mais je vais tenter de voir si Gomplate peut être un candidat pour aider à la génération de documentation dynamique.

Le projet

_Point de départ : Documentation de Gomplate

Préparation

  • Installation de Gomplate

Il existe de nombreuses méthodes pour installer Gomplate.

De mon côté, j'essaie en ce moment de privilégier l'utilisaton de asdf pour gérer mes utilitaires locaux et leurs versions.

La procédure n'étant pas détaillée dans la documentation officielle Gomplate, la voici ci-dessous :

  • Ajout du plugin
asdf plugin add gomplate
  • Installation de la version de gomplate souhaitée
asdf install gomplate v3.10.0
  • Activation pour tout le système
asdf global gomplate v3.10.0
  • Vérification de bon fonctionnement
gomplate --version
gomplate version 3.10.0

Ca fonctionne ! 👍

Découverte du fonctionnement de l'outil

Comment déclarer un template ?

Pour notre besoin, nous allons avoir besoin de pouvoir créer un (1) ou plusieurs fichiers d'entrée qui contiendront des variables que l'on souhaitera remplacer lors de la génération.

La documentation de la CLI parle de l'option -t pour un template mais cela ne semble pas être réellement notre besoin.

Par contre, la page de documentation sur la configuration mentionne des entrées qui semblent prométeuses inputFiles et inputDir. 🍾

Testons cela. 🚀

Test avec 1 seul template en entrée

Nous allons créer 2 fichiers pour ce test

test.tpl qui va simplement reprendre l'exemple de base de gomplate

Hello {{ .Env.USER }}

et le fichier .gomplate.yaml

inputFiles:
  - basic.tpl

Vérifions notre arborescence

tree -a
.
├── basic.tpl
└── .gomplate.yaml

0 directories, 2 files

Testons l'exécution de gomplate

gomplate
Hello jyg

Test avec plusieurs fichiers de template

Pour ce test, nous allons avoir une arborescence légèrement plus complexe avec l'ajout d'un dossier in dans lequel on va avoir 2 fois notre fichier précédent basic.tpl qui sera déposé (et légèrement édité).

tree -a -L 2
.
├── .gomplate.yaml
├── in
│   ├── basic2.tpl
│   └── basic.tpl

Nous faisons évoluer le fichier .gomplate comme ceci :

inputDir: in/

En exécutant gomplate on se rend compte qu'il n'y a pas d'output dans le terminal.

Par contre 2 fichiers on était créé à la racine de notre dossier :

tree -a -L 2
.
├── basic2.tpl
├── basic.tpl
├── .gomplate.yaml
├── in
│   ├── basic2.tpl
│   └── basic.tpl

et ces 2 fichiers contiennent bien la variable interprétée.

Il faut donc définir la valeur outputDir pour un mapping 1:1 ou outputMap si l'on souhaite pouvoir agir sur le nom des fichiers de sorti.

Exemple d'utilisation d'outputMap pour modifier l'extension du fichier de tpl à md (markdown).

inputDir: in/
outputMap: |
    out/{{ .in | strings.ReplaceAll ".tpl" ".md" }}

OK à priori, avec ces 2 directives nous devrions être en mesure de pouvoir avancer sur notre projet.

Implémentation du projet

Pour notre test, nous allons reprendre la structure simplifier d'un projet existant.

Quelques élements de contexte :

  • le projet sert de documentation,
  • chaque page de la documentation est un fichier markdown,
  • à la génération de la documentation, on souhaite être capable de récupérer ou injecter des variables, par exemple, la branche Git utilisée pour la génération,
  • on veut que les fichiers générés respectent l'arborescence initiale.

Préparation des dossiers et fichiers

tree -a -L 4
.
├── .gomplate.yaml
├── in
│   ├── en
│   │   ├── docker-compose.md
│   │   └── security
│   │       ├── cohesion.md
│   │       └── gitleaks.md
│   └── home.md

Les détails intéressants :

  • .gomplate.yaml
inputDir: in/
outputDir: out/
  • dans le fichier docker-compose.md on va définir la récupération d'une variable d'environnement représentant la branche Git.
# Docker-compose

## Docker-compose helper

...

```yaml
include:
  - project: '<group>/<project>/templates'
    ref: {{ env.Getenv "GITBRANCH" }}
    file: '/docker-compose.gitlab-ci.yml'
```

...

Exécution et vérification

On peut maintenant lancer la commande GITBRANCH=test gomplate et vérifiier les résultats.

  • ✅ le dossier out contient bien la même arborescence de fichiers ;
tree -a -L 4
.
├── .gomplate.yaml
├── in
│   ├── en
│   │   ├── docker-compose.md
│   │   └── security
│   │       ├── cohesion.md
│   │       └── gitleaks.md
│   └── home.md
└── out
    ├── en
    │   ├── docker-compose.md
    │   └── security
    │       ├── cohesion.md
    │       └── gitleaks.md
    └── home.md
  • ✅ la variable {{ env.Getenv "GITBRANCH" }}est bien remplacée par la valeur attendue ;

  • ✅ il est possible de définir une valeur par défaut {{ env.Getenv "GITBRANCH" "defaultbranch" }}

# Docker-compose

## Docker-compose helper

...

```yaml
include:
  - project: '<group>/<project>/templates'
    ref: test
    file: '/docker-compose.gitlab-ci.yml'
```

...

Conclusion

Gomplate répond plutôt bien à un besoin simple de génération / transformation de fichiers. En moins d'1 heure, en ne connaissant par l'outil, nous avons réussi à répondre à notre besoin, sans partir dans des outils plus complexes à installer et utiliser.

Le fait que Gomplate soit disponible comme un simple binaire facilite son installation et est donc très intéressant à utiliser aussi dans le cadre d'une CI.

Prochaines étapes

  • Creuser les fonctionnalités/fonctions natives de Gomplate, notamment l'utilisation des datasources ;
  • Voir l'utilisation de Gomplate en remplacement de envsubst ;