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:
- Repositório com o template do Hugo e o conteúdo
- 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.
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:
Se o processo ocorrer sem problemas, você vai ver todos os jobs com sucesso e o seu blog vai estar atualizado.
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.