Projeto 14 — CI/CD com GitHub Actions · Nível principiante → intermédio · Duração estimada: 1 h 30 a 2 h
Recebe um mini-sítio estático já ligado a dois workflows GitHub Actions funcionais. Clona, faz push, o sítio fica online. Altera uma cor em
config.json, volta a fazer push, a página pública atualiza-se sozinha. Termina por reparar três workflows defeituosos que ilustram os erros clássicos do CI/CD.
Acaba de ser contratado como júnior numa agência web. O primeiro trabalho: um mini-sítio «portfólio» a alojar gratuitamente. A consignação do chefe:
«Quero poder mudar a cor do sítio ao alterar um único ficheiro, fazer um
git pushe que se atualize sozinho. Sem FTP, sem servidor para administrar.»
O sénior da equipa já escreveu os dois workflows GitHub Actions e o script de build. O seu trabalho:
git clone + push + ativação do Pages).config.json com as suas informações e as suas cores.push → Pages funciona ao mudar a cor pelo menos duas vezes.Este projeto não é um TP em que escreve YAML a partir do zero. É um TP em que toma conta de uma cadeia CI/CD já no sítio, como numa equipa real: não reinventa os workflows, compreende-os, personaliza-os, diagnostica-os.
Este documento é autónomo. Nenhum curso externo a abrir para o terminar.
O GitHub Actions é um motor de execução integrado no GitHub. Em cada evento (push, pull_request, temporizador, botão manual), lança workflows descritos em YAML, em runners (VMs Ubuntu / Windows / macOS gratuitas para repositórios públicos).
name: Mon premier workflow # affiche dans l'UI
on: # QUAND s'executer
push:
branches: [main]
jobs: # QUOI faire (>= 1 job)
construire: # nom libre du job
runs-on: ubuntu-latest # OU s'executer (image de la VM)
steps: # les etapes du job
- uses: actions/checkout@v4 # etape "action reutilisable"
- run: echo "Bonjour" # etape "commande shell"Dois tipos de etapas:
uses: chama uma action publicada (actions/checkout@v4, actions/setup-python@v5, etc.).run: executa um comando shell no runner.on: | Acionado quando… |
|---|---|
push: { branches: [main] } | Faz-se push de um commit para main |
pull_request: { branches: [main] } | Alguém abre / atualiza uma PR para main |
schedule: [{ cron: "0 6 * * *" }] | Todos os dias às 06:00 UTC |
workflow_dispatch: | Botão manual no separador Actions |
O mesmo workflow pode ter vários acionadores ao mesmo tempo — é o caso de deployer-pages.yml (push + manual).
O GitHub Pages é um alojamento estático oferecido com cada repositório público. Publica-se HTML/CSS/JS por um dos métodos seguintes:
gh-pages (método antigo)./docs de main (outro método).O URL público é https://<utilisateur>.github.io/<nom-du-depot>/ — acessível a partir de qualquer navegador.
Para publicar a partir de Actions, deployer-pages.yml encadeia três actions oficiais:
Restrição capital: o job que publica precisa de permissões particulares, senão obtém-se Resource not accessible by integration. O workflow fornecido já as declara:
permissions:
contents: read
pages: write
id-token: writeÉ também a avaria 1 da missão 3 — retenha-a.
Em cada execução, o GitHub Actions expõe variáveis de ambiente úteis:
| Variável | Conteúdo |
|---|---|
GITHUB_SHA | O SHA do commit que acionou o run |
GITHUB_REF_NAME | O nome do ramo (main, feature-x, etc.) |
GITHUB_RUN_NUMBER | Um contador que incrementa em cada run |
Neste projeto, outils/build.py lê estas três variáveis para as mostrar na página publicada. Prova visual de que a implantação vem mesmo de Actions e não de um python build.py em local.
Ciclo final esperado — deve reproduzi-lo pelo menos 2 vezes:
site/config.json no VS Code.couleur_fond (por exemplo #0f172a → #7c3aed).git add site/config.json && git commit -m "changement de fond" && git push.https://<vous>.github.io/<depot>/ → o fundo está violeta.projet14-github-actions-pages-tp/
├── 00-ENONCE.md <- este documento
├── 02-CORRECTION.md <- solucoes detalhadas (a ler DEPOIS de tentar)
├── README.md
│
├── site/ <- O SITIO (fonte)
│ ├── config.json <- VOCE ALTERA : cores, titulo, autor
│ └── src/
│ ├── index.html.template <- modelo HTML (marcadores {{...}})
│ └── css/
│ └── style.css.template <- modelo CSS (marcadores {{...}})
│
├── outils/
│ └── build.py <- FORNECIDO — a nao modificar
│
├── .github/ <- WORKFLOWS JA FUNCIONAIS
│ └── workflows/
│ ├── deployer-pages.yml <- build + publica no Pages
│ └── verifier-config.yml <- valida config.json em PR
│
├── casses/ <- 3 workflows defeituosos (Missao 3)
│ ├── casse-1-permissions-manquantes.yml
│ ├── casse-2-declencheur-errone.yml
│ └── casse-3-chemin-artefact.yml
│
└── .gitignore <- ignore dist/Ponto importante: os dois workflows já estão em .github/workflows/. Não tem nada a escrever para a parte de implantação — apenas a compreender o que se passa e a personalizar config.json.
outils/build.py — é o contrato entre config.json e o HTML/CSS final.dist/: figura no .gitignore e é reconstruída em cada run.git --version).python --version — para testar build.py em local).projet14-github-actions-pages-tp/ no seu disco.projet14-actions-pages..gitignore (já fornecidos).A partir da raiz do projeto:
python .\outils\build.pyDeve ver:
OK dist/index.html genere
OK dist/css/style.css genere
--- Substitutions appliquees ---
{{TITRE}} -> Mon premier site pilote par GitHub Actions
{{COULEUR_FOND}} -> #0f172a
...Abra dist/index.html num navegador: vê o sítio com o fundo escuro por omissão. Se funcionar em local, funcionará no Actions.
git init
git branch -M main
git add .
git commit -m "point de depart projet14"
git remote add origin https://github.com/<votre-utilisateur>/projet14-actions-pages.git
git push -u origin mainSeparador Actions do seu repositório → aparece um run intitulado Deployer sur GitHub Pages. Espere que fique verde (~40 segundos após o push).
No fim do job deployer, uma mensagem anuncia:
Your site is live at https://<vous>.github.io/projet14-actions-pages/Clique → vê o seu sítio publicado.
config.json (20 pontos)Abra site/config.json e altere pelo menos:
titre — coloque o seu nome ou o de um projeto fictício.auteur — o seu nome.couleur_fond — no formato #RRGGBB (por exemplo #7c3aed, #dc2626, #0891b2).Verifique com python .\outils\build.py que o build continua a passar. Um formato errado (rouge, #ff, RGB(255,0,0)) é detetado por build.py e bloqueará o workflow.
Restrição: não parta o JSON. Uma vírgula a mais, uma chaveta em falta → workflow vermelho no GitHub.
Isto é o coração do projeto. Deve demonstrar que o ciclo CI/CD funciona, ao acioná-lo pelo menos duas vezes:
site/config.json (mude couleur_fond por exemplo para #dc2626 — vermelho).git add site/config.json && git commit -m "fond en rouge" && git push.https://<vous>.github.io/<votre-depot>/ → o fundo está vermelho.#16a34a, azul #0891b2, violeta #7c3aed, à sua escolha).Prova a fornecer no relatório:
git log --oneline).Ponto-chave: na página pública, um cartão mostra Commit SHA : <7 caractères>. Este SHA corresponde ao último commit em main. É a prova visual de que a página vem mesmo de Actions.
A pasta casses/ contém três workflows defeituosos, cada um a ilustrar um erro clássico. Para cada um:
.github/workflows/ (ao lado dos workflows oficiais)..github/workflows/ (não em casses/ — o original permanece defeituoso).| Ficheiro | Sintoma esperado |
|---|---|
casse-1-permissions-manquantes.yml | O job deployer falha com Resource not accessible by integration |
casse-2-declencheur-errone.yml | Nenhum run é acionado: o workflow é ignorado em silêncio |
casse-3-chemin-artefact.yml | O job construire falha com Error: Path does not exist: ./public |
Truque importante: pode lançar cada workflow manualmente via Run workflow no separador Actions, sem ter de fazer um commit verdadeiro em cada teste. Os workflows defeituosos têm todos um workflow_dispatch: ou pode acrescentá-lo temporariamente.
Prova a fornecer para cada avaria: captura do run vermelho antes, diff da correção, captura do run verde depois.
À escolha, um só basta:
a) Acrescente um badge de estado num README.md na raiz do seu repositório GitHub (não o do TP):
Mostra passing (verde) ou failing (vermelho) em direto.
b) Crie uma PR de teste com um config.json voluntariamente inválido (por exemplo "couleur_fond": "rouge"). O workflow Verifier la configuration deve falhar e bloquear o merge. Forneça a captura do bloqueio.
c) Crie um terceiro workflow manual (workflow_dispatch:) que envia uma notificação curl a um webhook (URL fornecido via Settings → Secrets, nunca em claro no YAML).
Um RAPPORT.md na raiz do seu repositório, contendo:
https://<vous>.github.io/<depot>/).on: push sem precisar branches: — quando é acionado? Isto é um problema?id-token: write é necessário para publicar no GitHub Pages? Para que serve o token OIDC?git push em main ao mesmo tempo? O bloco concurrency muda o quê no comportamento?API_KEY em Settings → Secrets. O código do workflow pode lê-lo via ${{ secrets.API_KEY }}. Pode ser impresso nos logs? Por que o GitHub mascara certos valores?deployer-pages.yml e verifier-config.yml. O segundo é inútil já que o primeiro faz o mesmo build? Justifique por que são complementares.build.py criasse um ficheiro historique.log? Onde seria preciso guardá-lo?| Elemento | Pontos |
|---|---|
Missão 1 — config.json personalizado e build local OK | 20 |
| Missão 2 — Prova do ciclo push → Pages (2 cores + capturas + SHAs) | 30 |
| Missão 3 — 3 avarias diagnosticadas e reparadas | 30 |
| Qualidade do relatório (estrutura, capturas, explicações) | 20 |
| Bónus — Missão 4 | +10 |
| Total | 100 (+10) |
Penalizações:
.github/workflows/ (logo ignorado pelo GitHub).dist/ commitada (deve permanecer no .gitignore).outils/build.py.# Squelette de reference d'un workflow
name: Description humaine
on: # QUAND
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch: # bouton manuel
permissions: # SEULEMENT ce qui est necessaire
contents: read
pages: write
concurrency: # ne pas empiler les runs
group: pages
cancel-in-progress: false
jobs:
mon-job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Une commande
run: python outils/build.pyOs 5 gestos que salvam no diagnóstico:
Re-run failed jobs: relança apenas as etapas em falha, mais rápido.workflow_dispatch: acrescente-o aos seus workflows para os poder relançar manualmente sem um commit vazio.echo "::debug::mon message": imprime uma mensagem de debug nos logs.site/config.jsonÉ o único ficheiro que deve modificar em tempo normal.
{
"titre": "Mon premier site pilote par GitHub Actions",
"sous_titre": "Change une couleur, fais un push, et regarde GitHub Pages se mettre a jour tout seul.",
"couleur_fond": "#0f172a",
"couleur_texte": "#f1f5f9",
"couleur_accent": "#38bdf8",
"auteur": "Etudiant du cours AOA-DEVOPS-101",
"version": "1.0.0"
}Restrições do ficheiro:
couleur_fond, couleur_texte, couleur_accent) devem respeitar o formato #RRGGBB — senão build.py rejeita.site/src/index.html.templateModelo HTML em que cada {{MARQUEUR}} é substituído por build.py. A página mostrará:
config.json).config.json).GITHUB_* do runner).O ficheiro completo é fornecido em site/src/index.html.template.
site/src/css/style.css.templateModelo CSS que usa {{COULEUR_FOND}}, {{COULEUR_TEXTE}} e {{COULEUR_ACCENT}} num bloco :root.
Excerto:
:root {
--fond: {{COULEUR_FOND}};
--texte: {{COULEUR_TEXTE}};
--accent: {{COULEUR_ACCENT}};
}
body {
background: var(--fond);
color: var(--texte);
}.github/workflows/deployer-pages.ymlname: Deployer sur GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
construire:
name: Construire le site
runs-on: ubuntu-latest
steps:
- name: Recuperer le code
uses: actions/checkout@v4
- name: Installer Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Generer dist/ a partir de config.json
run: python outils/build.py
- name: Preparer le dossier a publier
uses: actions/upload-pages-artifact@v3
with:
path: dist
deployer:
name: Publier sur GitHub Pages
needs: construire
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.publication.outputs.page_url }}
steps:
- name: Publier l'artefact
id: publication
uses: actions/deploy-pages@v4Leitura linha a linha: ver 02-CORRECTION.md → Missão 2.
.github/workflows/verifier-config.ymlname: Verifier la configuration
on:
pull_request:
branches: [main]
push:
branches-ignore: [main]
jobs:
linter:
name: Valider config.json
runs-on: ubuntu-latest
steps:
- name: Recuperer le code
uses: actions/checkout@v4
- name: Installer Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Construire en dry-run
run: python outils/build.py
- name: Verifier que dist/ est bien genere
run: |
test -f dist/index.html
test -f dist/css/style.css
echo "OK - site construit sans erreur"outils/build.py faz quatro coisas:
site/config.json.#RRGGBB (regex).{{MARQUEUR}} nos dois modelos e escreve o resultado em dist/.No GitHub Actions, as variáveis GITHUB_SHA, GITHUB_REF_NAME, GITHUB_RUN_NUMBER estão automaticamente disponíveis. Em local, não existem → o script mostra local-* no lugar. É assim que se distingue uma página mesmo implantada por Actions de uma página construída em local.
casses/casse-1-permissions-manquantes.ymlO workflow corre mas o job deployer falha com:
Error: Resource not accessible by integrationPergunta a colocar a si mesmo: que secção inteira falta, no topo do ficheiro, ao lado de on:?
casses/casse-2-declencheur-errone.ymlUm push em main nunca aciona este workflow. Nenhum run aparece. Nenhum erro.
Pergunta a colocar a si mesmo: leia a chave sob on:. O GitHub espera push, mas o que está escrito?
casses/casse-3-chemin-artefact.ymlbuild.py tem sucesso e mostra OK dist/index.html genere. Mas upload-pages-artifact falha com:
Error: Path does not exist: ./publicPergunta a colocar a si mesmo: onde build.py escreve o sítio (olhe para o código Python)? Que path: é preciso então pôr no workflow?
Curso criado pelo Dr. Haythem REHOUMA — Desenvolvimento e implantação de soluções de dados