Hugo + Gitlab + Firebase = 🚀

Par Jean-Philippe Lemelin | 10 April, 2018

La semaine dernière, nous avons dĂ©cidĂ© d’abandonner WordPress pour notre site web et de passer Ă  Hugo pour gĂ©nĂ©rer notre site web et l’hĂ©berger avec Firebase Hosting.

WordPress est un CMS (Content Management System / System de gestion de contenu) et par conséquent tout le workflow de création se passe dans un navigateur Web.

Hugo est un outil open-source Ă©crit en Go qui permet de gĂ©nĂ©rer des sites web statiques. Hugo va gĂ©nĂ©rer les pages HTML Ă  partir de chaque entrĂ©e de blog Ă©crit en Markdown, en fonction d’un certain template. D’un point de vue de dĂ©veloppeur, la gestion de fichier Markdown est beaucoup plus simple. De plus, les fichiers Markdown et template peuvent très facilement ĂŞtre entreposĂ©s dans Git (Source-control / Gestion de versions).

Vue d’ensemble

  1. L’auteur du blog modifie son billet en local tout en prĂ©visualisant le rĂ©sultat.
  2. L’auteur pousse ses modifications dans le dĂ©pĂ´t remote git push, dans ce cas-ci GitLab.
    • Il est aussi possible de mettre en place un système de revue via les Merge Request ou Pull Request.
  3. Ă€ l’aide d’un pipeline, GitLab va effectuer le dĂ©ploiement automatiquement vers FireBase Hosting.
  4. Un visiteur peut consulter le nouveau billet de façon sécuritaire (SSL).

Pourquoi ces choix ?

Hugo

  • Supporte le Markdown
  • Plusieurs thèmes sont disponibles
  • Compile le contenue de manière statique (rapide lors de la visualisation du contenu)
  • Serveur local, ce qui permet de prĂ©visualiser le rĂ©sultat localement
  • Super rapide

Exemple de Build:

$ hugo

                   | FR
+------------------+-----+
  Pages            |  35
  Paginator pages  |   0
  Non-page files   |   0
  Static files     | 115
  Processed images |   0
  Aliases          |  14
  Sitemaps         |   1
  Cleaned          |   0

Total in 50 ms

Firebase Hosting

  • Gratuit avec Spark Plan (1 GB de stockage et 10GB de bande passante par mois)
  • Permet d’utiliser son propre domaine ou sous-domaine, dans ce cas-ci UnicornPowered.com
  • CDN (Content-delivery Network) disponible dans le monde entier
  • SSL par dĂ©faut
  • L’upload peu se faire Ă  partir du command-line

Exemple de déploiement:

$ firebase deploy --token "$FIREBASE_TOKEN" --project ${FIREBASE_PROJECT}

=== Deploying to 'unicornpowered-website'...

i  deploying hosting
i  hosting: preparing public directory for upload...

âś”  hosting: 138 files uploaded successfully
âś”  Deploy complete!

Project Console: https://console.firebase.google.com/project/unicornpowered-website/overview
Hosting URL: https://unicornpowered-website.firebaseapp.com

Gitlab

  • DĂ©pĂ´ts privĂ©s illimitĂ©s
  • CI supportĂ© nativement avec pipeline et Docker

Configuration par Ă©tape

Installer Hugo

Simplement télécharger le binaire de Hugo (disponible ici) et le rajouter dans votre PATH.
Pour plus d’information, voir directement les instructions sur leur site web.

Créer un nouveau site avec Hugo

# create a new site
hugo new site <name of your new site>

# create a new content under post/ folder
hugo new post/<name of the post>.md

# clone the desired theme
# List of themes https://themes.gohugo.io/
cd themes; git clone <url to your theme>

# modify the hugo configuration
code config.toml

# Start a local server of hugo
hugo server

Création du projet Firebase

Pour utiliser Firebase vous devez avoir un compte Google et vous authentifier ici.

Cliquez sur “GO TO CONSOLE”, crĂ©er un projet en lui donnant un nom.

Installation du Firebase CLI Tools et configuration

Le firebase tools permet de tĂ©lĂ©verser le contenu d’un site web vers Firebase Hosting, le tout en command line.

# Node JS is required, install it first if you don't have it yet
# You can use homebrew or download the installer from the official site https://nodejs.org

$ npm install -g firebase-tools

# check firebase tools version
$ firebase --version

# Login
$ firebase login

# List project
$ firebase list

Ensuite, on doit initialiser Firebase Ă  l’aide de la commande: firebase init

Il va vous poser les questions suivantes:

  • Which Firebase CLI features do you want to setup? RĂ©ponse: Hosting.
  • Select a default Firebase project for this directory RĂ©ponse: SĂ©lectionner le projet que vous avez crĂ©Ă© prĂ©cĂ©demment.
  • Do you want to use as your public directory? RĂ©ponse: Yes.
  • Configure as a single-page app? RĂ©ponse: No.
$ firebase init
âš   JSON error trying to load /home/jp/up/website/.firebaserc

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /home/jp/up/website

Before we get started, keep in mind:

  * You are initializing in an existing Firebase project directory

? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confir
m your choices. Hosting: Configure and deploy Firebase Hosting sites

=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.

? Select a default Firebase project for this directory: UnicornPowered-website-staging (unicornpowered-website-staging)

=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
âś”  Wrote public/404.html
âś”  Wrote public/index.html

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

âś”  Firebase initialization complete!

Il devrait vous avoir créé un fichier firebase.json à la racine de votre projet.

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}

Assurez-vous d’ajouter ce fichier au dĂ©pĂ´t.

Vous pouvez effectuer un test de déploiement à partir de votre machine. Assurez-vous de passer le bon --baseURL à Hugo.

# Build your website
$ hugo --baseURL "https://your-projet-subdomain-name.firebaseapp.com/"

# Deploy it
$ firebase deploy --only hosting

Génération du FIREBASE_TOKEN

Afin d’automatiser le dĂ©ploiement, nous devons gĂ©nĂ©rer un token pour permettre Ă  la machine de build de s’authentifier Ă  Firebase via le Firebase CLI. Pour ce faire, exĂ©cuter la commande firebase login:ci

$ firebase login:ci

Waiting for authentication...

âś”  Success! Use this token to login on a CI server:

<your token will be shown here>

Example: firebase deploy --token "$FIREBASE_TOKEN"

Ensuite, il faut ajouter le token en tant que secret dans GitLab.

Configuration du pipeline de GitLab

Pour activer les pipelines de GitLab, il suffit d’ajouter un fichier .gitlab-ci.yml Ă  la racine de votre projet.

Voici un exemple de .gitlab-ci.yml. Dans celui-ci, nous avons un pipeline de 2 Ă©tapes (stages), soit un build et un deploy. Le build est effectuĂ© Ă  partir d’une image docker de hugo, tandis que le deploy est effectuĂ© Ă  partir d’une image de node puisque le firebase-tools est disponible sur npm.

stages:
  - build
  - deploy

build:
  stage: build
  # All available Hugo versions are listed here: https://gitlab.com/pages/hugo/container_registry
  image: registry.gitlab.com/pages/hugo:0.32.3
  artifacts:
    paths:
      - public/
    expire_in: 1 day
  variables:
    BASE_URL: "https://unicornpowered-website.firebaseapp.com/"
    HUGO_ENV: "production"
    GIT_SUBMODULE_STRATEGY: recursive
  script:
  - hugo --baseURL $BASE_URL
    only:
   - master

deploy:
  stage: deploy
  image: node:latest
  dependencies:
   - build
  script:
   - npm install -g firebase-tools
   - firebase deploy --token "$FIREBASE_TOKEN" --project unicornpowered-website --non-interactive --only hosting --message "Pipeline $CI_PIPELINE_ID, build $CI_JOB_ID, sha1 $CI_COMMIT_SHA, ref $CI_COMMIT_REF_NAME"
  only:
   - master

Dans votre cas, ne pas oublier de changer le BASE_URL et le nom du projet de Firebase (voir l’argument --project).

Bonus .gitlab-ci.yml avec environnement de staging et de production

Voici notre .gitlab-ci.yml qui est utilisé pour notre site web. Celui-ci contient un environnement de staging pour la branche dev et un environnement de production pour la branche master. De plus, une étape de test est aussi faite avec html-proofer.

variables:
  PROD_HUGO_ENV: "production"
  PROD_BASE_URL: "https://unicornpowered.com/"
  PROD_DOMAIN: "unicornpowered.com"
  PROD_FIREBASE_PROJECT: "unicornpowered-website"

  STAGING_HUGO_ENV: "development"
  STAGING_BASE_URL: "https://staging.unicornpowered.com/"
  STAGING_DOMAIN: "staging.unicornpowered.com"
  STAGING_FIREBASE_PROJECT: "unicornpowered-website-staging"

.staging_variables: &staging_variables
  HUGO_ENV: ${STAGING_HUGO_ENV}
  BASE_URL: ${STAGING_BASE_URL}
  DOMAIN: ${STAGING_DOMAIN}
  FIREBASE_PROJECT: ${STAGING_FIREBASE_PROJECT}

.production_variables: &production_variables
  HUGO_ENV: ${PROD_HUGO_ENV}
  BASE_URL: ${PROD_BASE_URL}
  DOMAIN: ${PROD_DOMAIN}
  FIREBASE_PROJECT: ${PROD_FIREBASE_PROJECT}

stages:
  - build
  - test
  - deploy

# ====

.build_base: &build_base
  stage: build
  # All available Hugo versions are listed here: https://gitlab.com/pages/hugo/container_registry
  image: registry.gitlab.com/pages/hugo:0.38.2
  artifacts:
    paths:
      - public/
    expire_in: 1 day
  script:
  - export
  - hugo --baseURL ${BASE_URL}


build:staging:
  <<: *build_base
  variables:
    <<: *staging_variables
    GIT_SUBMODULE_STRATEGY: recursive
  only:
   - dev

build:production:
  <<: *build_base
  variables:
    <<: *production_variables
    GIT_SUBMODULE_STRATEGY: recursive
  only:
   - master

# ====

.test_base: &test_base
  stage: test
  image: 18fgsa/html-proofer:gitlab-ci
  script:
    - htmlproofer public
       --log-level :debug
       --check-favicon
       --check-img-http
       --allow-hash-href
       --empty-alt-ignore

       --check-external-hash
       --internal-domains ${DOMAIN}

test:staging:
  <<: *test_base
  variables:
    <<: *staging_variables
  dependencies:
   - build:staging
  only:
   - dev

test:production:
  <<: *test_base
  variables:
    <<: *production_variables
  dependencies:
   - build:production
  only:
   - master

# ====

.deploy_base: &deploy_base
  stage: deploy
  image: node:alpine
  cache:
    paths:
    - node_modules/
  script:
   - npm install -g firebase-tools
   - firebase deploy --token "$FIREBASE_TOKEN" --debug --project ${FIREBASE_PROJECT} --non-interactive --only hosting --message "Pipeline $CI_PIPELINE_ID, build $CI_JOB_ID, sha1 $CI_COMMIT_SHA, ref $CI_COMMIT_REF_NAME"


deploy:staging:
  <<: *deploy_base
  variables:
    <<: *staging_variables
  dependencies:
   - build:staging
  only:
   - dev

deploy:production:
  <<: *deploy_base
  variables:
    <<: *production_variables
  dependencies:
   - build:production
  only:
   - master

JP, GL HF 🦄

comments powered by Disqus