Documentación técnica con multilenguaje usando CI/CD y GitLab

docs_gitlab_CI-CD

En los últimos años, los generadores de sitios estáticos o SSG (del inglés Static Site Generator) se han convertido en herramientas muy populares para la creación de páginas web. Este tipo de sitios web destacan por su sencillez, rendimiento y seguridad. Al compararlos con las webs construidas mediante los sistemas de gestión de contenidos o CMS (del inglés Content Management System) se reduce la complejidad y se eliminan sobrecargas innecesarias y vulnerabilidades. Sin embargo, al prescindir de una base de datos, no se puede servir contenido dinámico. Esto quiere decir que la limitación que existe es que el servidor sólo puede devolver el contenido que se haya compilado previamente y no permite realizar cambios en tiempo real. Entre los SSG más valorados1, se encuentran NestJS, Hugo, Gatsby, Mkdocs, Jekyll y Sphinx.

A continuación, utilizando las opciones de CI/CD que proporciona GitLab se detallan los pasos para desplegar una página web estática generada con Mkdocs y Hugo. Además, en el caso de Mkdocs, se utilizará pandoc para generar un documento PDF compilado a través de LaTeX. Ambos ejemplos contarán con la opción de multilenguaje.

Índice de Contenidos

Documentación con Mkdocs

Mkdocs es un generador de sitios estáticos rápido y sencillo que está orientado a la construcción de documentación de proyectos. Los ficheros de la documentación se escriben en Markdown, y se configuran con un archivo YAML. Como tema se utilizará Material for MkDocs y posteriormente, utilizando pandoc se convertirán los archivos markdown a un archivo PDF compilado mediante la plantilla Eisvogel de LaTeX. Se creará un archivo PDF para los distintos lenguajes utilizados.

Esta publicación detalla lo que se ha realizado en el repositorio mkdocs-material que es una plantilla para desplegar rápidamente la documentación. Se recomienda tener dicho repositorio de referencia.

Material for Mkdocs
Material for Mkdocs
PortadaÍndice
PortadaÍndice
ImágenesPrimer capítulo
ImágenesPrimer capítulo

Instalación y creación del proyecto

En primer lugar, se instalará material for mkdocs utilizando pip install mkdocs-material o se usará mediante la imagen oficial docker pull squidfunk/mkdocs-material. Una vez instalado se creará un nuevo proyecto con:

Alternativamente, si se está utilizando Docker:

Lo anterior creará la siguiente estructura:

.
├─ docs/
│  └─ index.md
└─ mkdocs.yml

Según esta discusión del proyecto mkdocs-material, para habilitar el multilenguaje y poder modificar las imágenes actualizaremos la estructura del proyecto a la mostrada a continuación. Es importante tener en cuenta que se crean dos archivos de configuración mkdocs.yml y pdf_metadata_***.md distintos para cada lenguaje, su contenido se muestra un poco más abajo. Además, las imágenes se guardarán en overrides/assets/images/ y las plantillas de latex se guardan en el directorio latex-templates, aunque únicamente utilizaremos la plantilla eisvogel.latex.

.
├── config
│   ├── en
│   │   └── mkdocs.yml
│   └── es
│       └── mkdocs.yml
├── docs
│   ├── en
│   │   ├── index.md
│   │   └── example.md
│   └── es
│       ├── index.md
│       └── example.md
├── latex-templates
│   ├── default.latex
│   ├── eisvogel.latex
│   └── pandoc-scholar.latex
├── overrides
│   └── assets
│       └── images
│           ├── favicon.ico
│           ├── logo-red.svg
│           └── logo.svg
├── pdf_metadata_esp.md
└── pdf_metadata_eng.md

El contenido del archivo config/es/mkdocs.yml es el siguiente:

site_name: Docs Name
site_description: Descripción...

docs_dir: '../../docs/es'                          # Where to find the Spanish markdown files
site_dir: '../../public/es'                        # Where to put the Spanish HTML files

repo_url: https://lab.gsi.upm.es/docs/mkdocs-material/
edit_uri: edit/main/docs/

nav:
  - Inicio: index.md
  - Ejemplo: example.md

theme:
  name: material
  language: es
  custom_dir: '../../overrides/'                  # This is where the customization of the theme lives
  logo: assets/images/logo-red.svg                # The logo is shared by all languages
  favicon: assets/images/favicon.ico              # The favicon is shared by all languages
  include_search_page: true
  search_index_only: true
  palette:
    # Light mode
    - media: "(prefers-color-scheme: light)"
      scheme: default
      primary: indigo
      accent: indigo
      toggle:
        icon: material/toggle-switch-off-outline
        name: Switch to dark mode
    # Dark mode
    - media: "(prefers-color-scheme: dark)"
      scheme: slate
      primary: blue
      accent: blue
      toggle:
        icon: material/toggle-switch
        name: Switch to light mode

plugins:
  - search
  - minify:
      minify_html: true
      minify_js: true
      htmlmin_opts:
          remove_comments: true
  - pandoc:
      enabled_if_env: ENABLE_PANDOC_EXPORT
      combined: true
      combined_output_path: docs.pdf
  - git-revision-date-localized:
      timezone: Europe/Madrid
      locale: es
      fallback_to_build_date: false
      enable_creation_date: true

markdown_extensions:
  - toc:
      permalink: "#"
      toc_depth: 3
  - attr_list
  - footnotes
  - pymdownx.tasklist:
      custom_checkbox: true

extra:
  social:
    - icon: fontawesome/brands/gitlab
      link: https://lab.gsi.upm.es/docs/mkdocs-material
    - icon: fontawesome/brands/gitter
      link: https://gitter.im/repo
    - icon: fontawesome/brands/docker
      link: https://lab.gsi.upm.es/docs/mkdocs-material/container_registry
    - icon: fontawesome/brands/twitter
      link: https://twitter.com/
  alternate:
  - link: /docs/mkdocs-material/
    name: en - English
    lang: en
  - link: /docs/mkdocs-material/es/
    name: es - español
    lang: es

Mientras que el contenido del archivo config/en/mkdocs.yml es el siguiente:

site_name: Docs Name
site_description: Description...

docs_dir: '../../docs/en'                          # Where to find the English markdown files
site_dir: '../../public/en'                        # Where to put the English HTML files

repo_url: https://lab.gsi.upm.es/docs/mkdocs-material/
edit_uri: edit/main/docs/

nav:
  - Home: index.md
  - Example: example.md

theme:
  name: material
  language: en
  custom_dir: '../../overrides/'                  # This is where the customization of the theme lives
  logo: assets/images/logo-red.svg                # The logo is shared by all languages
  favicon: assets/images/favicon.ico              # The favicon is shared by all languages
  include_search_page: true
  search_index_only: true
  palette:
    # Light mode
    - media: "(prefers-color-scheme: light)"
      scheme: default
      primary: indigo
      accent: indigo
      toggle:
        icon: material/toggle-switch-off-outline
        name: Switch to dark mode
    # Dark mode
    - media: "(prefers-color-scheme: dark)"
      scheme: slate
      primary: blue
      accent: blue
      toggle:
        icon: material/toggle-switch
        name: Switch to light mode

plugins:
  - search
  - minify:
      minify_html: true
      minify_js: true
      htmlmin_opts:
          remove_comments: true
  - pandoc:
      enabled_if_env: ENABLE_PANDOC_EXPORT
      combined: true
      combined_output_path: docs.pdf
  - git-revision-date-localized:
      timezone: Europe/Madrid
      locale: en
      fallback_to_build_date: false
      enable_creation_date: false

markdown_extensions:
  - toc:
      permalink: "#"
      toc_depth: 3
  - attr_list
  - footnotes
  - pymdownx.tasklist:
      custom_checkbox: true

extra:
  social:
    - icon: fontawesome/brands/gitlab
      link: https://lab.gsi.upm.es/docs/mkdocs-material
    - icon: fontawesome/brands/gitter
      link: https://gitter.im/repo
    - icon: fontawesome/brands/docker
      link: https://lab.gsi.upm.es/docs/mkdocs-material/container_registry
    - icon: fontawesome/brands/twitter
      link: https://twitter.com/devops
  alternate:
  - link: /docs/mkdocs-material/
    name: en - English
    lang: en
  - link: /docs/mkdocs-material/es/
    name: es - español
    lang: es

En los archivos de configuración anteriores, cabe destacar varias opciones que permiten el multilenguaje:

  • Existen directorios distintos para los archivos markdown de origen y html de destino.
  • La barra de navegación es diferente para cada idioma.
  • El link de cada idioma es el mismo con la diferencia de que, en este caso, la versión inglesa es la que está por defecto y en la versión española se tiene que añadir el sufijo /es/.

Despliegue de la documentación en local

Es importante tener en cuenta que se han añadido varios plugins en los archivos de configuración, los cuales pueden ser fuentes de errores. Se utiliza mkdocs-pandoc-plugin para combinar todos los archivos markdown en uno único si la variable de entorno ENABLE_PANDOC_EXPORT equivale a 1. El plugin mkdocs-git-revision-date-localized-plugin sirve para visualizar la fecha de la última modificación git de una página. Se usa mkdocs-minify-plugin para simplificar archivos HTML y/o JS antes de ser escritos en el disco y el plugin mkdocs-redirects para crear redirecciones de páginas (por ejemplo, para páginas movidas/renombradas). Por lo tanto, se requiere instalar los plugins en función de si se usa mkdocs mediante Docker (recomendado) o pip. Otra opción, sería comentar las líneas de los plugins en los archivos mkdocs.yml.

  • Uso de mkdocs mediante Docker:

Por defecto la imagen oficial de docker squidfunk/mkdocs-material, tiene instalado los plugins mkdocs-minify-plugin y mkdocs-redirects. Por lo tanto, es necesario utilizar una imagen con los plugins mkdocs-pandoc-plugin y mkdocs-git-revision-date-localized-plugin instalados para que funcione correctamente. Existen varias opciones, utilizar la imagen registry.gsi.upm.es/docs/mkdocs-material, la imagen jtr0/mkdocs-material o construir una imagen de docker con los plugins extra que se requieran fijándose en la plantilla de Dockerfile.

La web estará accesible en http://localhost:8000/. Una pequeña desventaja es que no puede servir el sitio localmente con la función de multilenguje, únicamente funcionará cuando se despliegue en GitLab Pages.

  • Uso de mkdocs mediante pip:

Se requiere la instalación de los plugins mkdocs-minify-plugin, mkdocs-redirects, mkdocs-pandoc-plugin y mkdocs-git-revision-date-localized-plugin. Para ello se usará el siguiente comando:

Una vez instalados los plugins, se podrá servir la web en local y acceder en http://localhost:8000/.

mkdocs serve

Construcción de PDFs con pandoc y la plantilla de LaTeX Eisvogel

Durante la construcción del contenido público de la página web, se utiliza el plugin de pandoc para combinar todos los archivos markdown en uno. Se construirán tantas veces como idiomas distintos haya, por ejemplo en este caso se generarán dos documentos public/en/docs.pdf.md y public/es/docs.pdf.md:

Para compilar el pdf con pandoc y la plantilla de LaTeX Eisvogel se necesitan los archivos de metadatos del pdf (pdf_metadata_esp.md y pdf_metadata_eng.md), la plantilla Eisvogel (latex_templates/eisvogel.latex) almacenada dentro del docker y la combinación de los archivos markdown. Entonces, se requiere utilizar la imagen jtr0/latex-pandoc o construirse otra imagen a partir de este Dockerfile. Además, existen variables de configuración propias de la plantilla Eisvogel que se pueden consultar en su Github. Dichas variables se almacenarán en los archivos de metadatos, como se muestra en el ejemplo a continuación:

Por último, la generación de los PDFs se lleva a cabo mediante los siguientes comandos:

Despliegue en GitLab Pages

Para la configuración de CI/CD con GitLab, hay que crear un archivo .gitlab-ci.yml para que construya el sitio web y lo despliegue en GitLab Pages. En el siguiente ejemplo se establecen tres etapas, en la primera se construye la web con el plugin pandoc, en la segunda se despliega y en la última se generan los PDFs automáticamente.

stages:
  - build
  - deploy
  - pdfs 

build_mkdocs:
  image: 
    name: registry.gsi.upm.es/docs/mkdocs-material
    entrypoint: [""]
  stage: build 
  only:
    - main
  script:
    - export ENABLE_PANDOC_EXPORT=1
    - mkdir -p data/en
    - mkdir data/es
    - mkdocs build -f config/en/mkdocs.yml --verbose --site-dir ../../data/en --no-directory-urls 
    - mkdocs build -f config/es/mkdocs.yml --verbose --site-dir ../../data/es --no-directory-urls 
  artifacts:
    paths:
      - data

pages:
  image: 
    name: registry.gsi.upm.es/docs/mkdocs-material
    entrypoint: [""]
  stage: deploy
  only:
    - main
  script:
    - mkdir -p public/en
    - mkdir public/es
    - mkdocs build -f config/en/mkdocs.yml --verbose  --no-directory-urls 
    - mkdocs build -f config/es/mkdocs.yml --verbose  --no-directory-urls 
    - cp -r public/en/* public 
  artifacts:
    paths:
      - public

generate_pdfs:
  image: jtr0/latex-pandoc
  stage: pdfs
  only:
    - main
  script:
    - mkdir -p public/pdfs/en
    - mkdir public/pdfs/es
    - mkdir -p assets/images
    - cp -r overrides/assets/images /assets
    - cp -r overrides/assets/images/* assets/images
    # English pdf
    - pandoc -N --template=eisvogel.latex --listings -V lang=en --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 pdf_metadata_eng.md data/en/docs.pdf.md  --pdf-engine=xelatex --toc -o public/pdfs/en/eisvogel_template.pdf
    # Spanish pdfs
    - pandoc -N --template=eisvogel.latex --listings -V lang=es --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 pdf_metadata_esp.md data/es/docs.pdf.md  --pdf-engine=xelatex --toc -o public/pdfs/es/eisvogel_template.pdf
  artifacts:
    paths:
      - public/pdfs/

Una vez haya tenido éxito el pipeline, se podrá acceder a la documentación en la web en la dirección https://<gitlab-user>.gitlab.io/<project-name>/. Por otro lado, se podrán acceder a los artefactos generados con los pdfs en la url https://gitlab.com/<gitlab-user>/<project-name>/-/jobs/artifacts/main/download?job=generate_pdfs. En caso de tener el proyecto en un grupo, será necesario cambiar <gitlab-user> por <gitlab-group>. Además, GitLab permite añadir un dominio o subdominio a la documentación.

A continuación, se describe otro método para documentar proyectos a través del generador de páginas estáticas Hugo.

Documentación con Hugo

Hugo es un SSG escrito en Go, lanzado en 2013, y es capaz de generar la mayoría de las páginas web en pocos segundos (menos de 1 ms por página)2. También se usará el tema Learn, el cual está escrito en Go y es rápido, moderno y con función de multilenguaje.

Learn Hugo Theme
Learn Hugo Theme

Instalación y creación del proyecto

Lo primero es proceder a instalar Hugo siguiendo la documentación oficial dependiendo del sistema operativo utilizado. Lo segundo es escoger un tema para utilizar de plantilla. Por ejemplo, los temas más recomendados para documentación técnica son: Learn, Geekdoc, Techdoc, Ace documentation y Hugo Book. Se continúa creando un nuevo proyecto con el siguiente comando:

En este momento, es recomendable inicializar el repositorio git:

Para añadir el tema escogido, se necesita copiar el zip del tema en la nueva carpeta themes (recomendado) o añadir el submódulo del tema.

A continuación, edita el archivo de configuración config.toml y añade el nombre del directorio del tema:

baseURL = "http://localhost:1313/"
theme = "learn"

Sirva el sitio web en local, estará disponible en http://localhost:1313/.

Creación de capítulos y páginas

Para crear un nuevo capítulo llamado ejemplo se utiliza el comando:

Mientras que para crear una nueva entrada llamada ci_cd, se utiliza:

Despliegue en GitLab Pages

Lo primero es modificar el parámetro baseurl con esta estructura baseURL = "https://<gitlab-user>.gitlab.io/<project-name>/". Lo siguiente es realizar la configuración CI/CD en GitLab añadiendo un archivo .gitlab-ci.yml o pulsando en el. Concretamente, se utiliza la plantilla que se muestra a continuación para que realice un test básico en las ramas que no son la principal y el despliegue de la rama principal en GitLab Pages.

Por último, se recomienda habilitar la visibilidad para todos en el control de acceso a la página para que cualquier persona pueda acceder mediante la url. Dirigete a Settings > General and expand Visibility, project features, permissions > Pages > Everyone.


  1. Jamstack, Site Generators

  2. Chris Macrae, Hugo vs Jekyll: Benchmarked

Leave a Reply

Your email address will not be published. Required fields are marked *