Entrega contínua de blogs Hugo com GitHub Actions

Aprenda a agilizar o worflow de publicação do seu blog feito com Hugo usando entrega contínua (continuous delivery) com GitHub Actions para atualizar automaticamente a página no GitHub Pages.

5 min de leitura

O Hugo é hoje um dos melhores e mais populares geradores de sites estáticos. Já o GitHub Pages oferece um excelente serviço para distribuir gratuitamente conteúdos estáticos, o que é perfeito para blogs. Logo, é natural que as duas ferramentas sejam comumente usadas em conjunto.

A partir do momento que o blog estiver todo configurado, com todos os templates customizados da forma como queremos, o dia-a-dia do blog passa a revolver em torno da criação de conteúdo.

Existem várias formas de trabalhar, mas qualquer workflow escolhido terá um mínimo de passos comuns:

  • Criar um novo conteúdo (como posts, artigos, imagens, etc)
  • Rodar o comando hugo com alguma parametrização para gerar o conteúdo estático atualizado
  • Publicar o novo conteúdo estático no repositório <nomeusuario>.github.io

O restante deste artigo vai tratar de configurar um workflow usando GitHub Actions para automatizar o processo de gerar conteúdo estático e publicá-lo. Ao final, teremos um processo de entrega contínua para nosso blog.

Nosso esquema será esse: Commit na master -> Workflow GitHub Actions -> Blog github.io atualizado

A única ação necessária será um commit no branch master contendo as alterações desejadas. Estou usando este fluxo de trabalho e o considero bem fácil e prático.

O tutorial abaixo assume que você está usando dois repositórios:

  1. Repositório com o template do Hugo e o conteúdo
  2. Repositório <nomeusuario>.github.io

E tudo o que você precisa para implementá-lo é seguir os passos descritos abaixo.

#Configuração do workflow de CI/CD com GitHub Actions

Até uns dias atrás, eu nunca tinha trabalho com as ferramentas de CI/CD do GitHub. Mas o GitHub Actions se mostrou bastante fácil de aprender, especialmente para quem já tem alguma experiência com ferramentas de CI/CD como o Circle CI ou Travis.

O GitHub Actions chama os pipelines de workflows. Para criar um novo workflow, primeiro você deve criar, na raiz do repositório do seu blog (onde fica seu template), a seguinte estrutura de diretórios:

.github/workflows

Dentro você terá de adicionar um arquivo de workflow. Ele pode ter qualquer nome, e deve terminar com a extensão .yml ou .yaml.

Abaixo, podemos ver o workflow que estou usando no meu blog atualmente, já comentado. Você também pode baixar ele aqui.

name: Deploy para <nomeusuario>.github.io
on:
push:
  branches:
    - master # somente commits no branch master geram deploys
# Também pode rodar um deploy automaticamente todos os dias
# para publicar posts agendados (com datas futuras)
schedule:
  - cron: '0 8 * * *' # 08:00 am UTC

jobs:
# O job "build" é responsável por baixar o template, o hugo e
# compilar o site estático
build:
  name: Gerar conteúdo estático
  runs-on: ubuntu-latest
  steps:
      # Primeiro, fazemos checkout do repositório
    - uses: actions/checkout@master
      # Depois, usamos uma action para clonar o repositório do tema
      # Substitua o endereço e o diretório por um de sua preferência
    - name: Atualizar template
      uses: "srt32/git-actions@v0.0.3"
      with:
        args: "git clone https://github.com/htr3n/hyde-hyde.git themes/hyde-hyde"
      # Permite instalar qualquer versão do hugo que você precisar
    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
      with:
        hugo-version: '0.69.0' # se quiser a última, pode usar 'latest'
        extended: true # permite compilar SCSS e SASS
    - name: Build
      run: hugo # gera os arquivos estáticos
      # Esta action faz upload do diretório /public como artefato
      # do job "build"
    - name: Upload dos artefatos
      uses: actions/upload-artifact@v1
      with:
        name: public
        path: ./public
publish:
  name: Publish to <nomeusuario>.github.io
  runs-on: ubuntu-latest
  needs: build # o job "publish" só roda se deu tudo certo durante o "build"
  steps:
      # Primeiro fazemos checkout do nosso repositório github.io
      # no diretório static-site
    - uses: actions/checkout@v2
      with:
        repository: '<nomeusuario>/<nomeusuario>.github.io'
        # token com as permissões necessárias
        token: ${{ secrets.CD_BLOG_TOKEN }}
        path: static-site
      # Fazemos download dos artefatos do job "build" para o
      # diretório /public
    - name: Download dos artefatos
      uses: actions/download-artifact@v1
      with:
        name: public
      # Copiamos os novos arquivos estáticos em /public para /static-site
    - name: Aplicar atualização
      shell: bash
      run: |
        cp -r ./public/* ./static-site
      # Adicionamos as alterações e geramos um commit
    - name: Commit files
      run: |
        cd static-site
        git config --local user.email "<email-valido>"
        git config --local user.name "GitHub Action - Deploy"
        git add .
        git commit -m "Add changes" -a
      # Por último, precisamos fazer um push para o repositório github.io
      # de destino
    - name: Push changes
      uses: ad-m/github-push-action@master
      with:
        repository: '<nomeusuario>/<nomeusuario>.github.io'
        github_token: ${{ secrets.CD_BLOG_TOKEN }}
        directory: static-site

Sera necessário subsituir algumas variáveis no template, como o <nomeusuario>, o <email-valido>, e o template utilizado.

Além disso, você deve ter notado que em dois momentos precisamos de um token do GitHub, como nesta linha: github_token: ${{ secrets.CD_BLOG_TOKEN }}. É bem fácil gerar e cadastrar este token.

Settings/Developer settings/Personal access tokens/Generate new token

Permissões do token, habilitando a opção repo

Provavelmente, habitalando somente a opção "public_repo" já deve funcionar, mas não testei esta opção. Se você quiser testar, pode deixar um comentário contando se funcionou.

Feito isso, clique em Generate token e uma tela vai abrir. Salve este token, ele é importante. Agora, precisaremos criar um Secret no nosso repositório.

Navegue para as configurações do seu repositório, e na seção Secrets, cadastre um secret com o nome CD_BLOG_TOKEN, com o token como valor.

Feito isso, basta fazer um commit na master e o workflow será disparado. Você pode acompanhar o resultado em Actions:

Lista de execuções dos workflows

Se o processo ocorrer sem problemas, você vai ver todos os jobs com sucesso e o seu blog vai estar atualizado.

Lista de execuções dos workflows

#Agendamento de posts

Esta abordagem também permite a publicação automática de posts agendados. A resposta está no começo do workflow. Podemos configurar um agendamento através de uma expressão cron simples, como esta:

schedule:
- cron:  '0 0 5 * *'

Esta expressão descreve a frequência de deploy nos seguintes termos:

┌───────────── minuto (0 - 59) │ ┌───────────── hora (0 - 23) │ │ ┌───────────── dia do mês (1 - 31) │ │ │ ┌───────────── mês (1 - 12 ou JAN-DEZ) │ │ │ │ ┌───────────── dia da semana (0 - 6 ou DOM-SAB) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │


Assim, nossa expressão 0 0 5 * * significa que o workflow deve ser disparado todos os dias, de todos os meses, às 5 horas da manhã.

No cabeçalho dos nossos posts, precisamos definir a data de postagem:

+++
author = "John Connor"
title = "Post agendado para o futuro longínquo"
date = "2032-07-03"
+++

Se publicarmos este post com data futura para o branch master, por padrão o Hugo não vai incluí-lo na geração do site. O workflow será executado todos os dias às 5 horas da manhã, até o dia 3 de julho de 2032, a data agendada para esta postagem, e ela será incluída na publicação do site deste dia em diante.

#Trabalhando com branches

Por fim, esta abordagem também nos permite escrever os posts em branches individuais, sem marcar os posts com draft = true. Eu crio branches no formato post/nome-do-branch. Quando está pronto, é só fazer merge para o branch master que o processo vai ser disparado.

E é isso. Espero que essas dicas sejam úteis. E se você usa alguma outra estratégia ou tem alguma dica útil, compartilhe nos comentários.

Gostou do artigo? Compartilhe nas redes sociais ou deixe um comentário abaixo!

Comentários