Este documento contém as soluções completas das 4 missões, as explicações linha a linha dos workflows fornecidos, as reparações das 3 avarias e as respostas às questões de reflexão.
Abra-o só depois de ter tentado de verdade. Ler a solução antes de ter tateado é perder 80 % da aprendizagem.
config.jsonExemplo de ficheiro válido:
{
"titre": "Portfolio de <votre nom>",
"sous_titre": "Deploiement automatique via GitHub Actions",
"couleur_fond": "#7c3aed",
"couleur_texte": "#f8fafc",
"couleur_accent": "#22d3ee",
"auteur": "<Votre Nom>",
"version": "1.0.0"
}Pontos a respeitar:
titre, sous_titre, couleur_fond, couleur_texte, couleur_accent, auteur, version) são obrigatórias.#RRGGBB (6 caracteres hexadecimais depois do #).Validação local:
python .\outils\build.pyDeve mostrar OK dist/index.html genere e OK dist/css/style.css genere. Qualquer erro ERREUR : interrompe o script e bloqueará depois o workflow GitHub.
Paleta sugerida para testar o ciclo na missão 2:
| Cor | Fundo | Texto | Destaque |
|---|---|---|---|
| Noite escura | #0f172a | #f1f5f9 | #38bdf8 |
| Violeta vibrante | #7c3aed | #f8fafc | #22d3ee |
| Vermelho vivo | #dc2626 | #fef2f2 | #facc15 |
| Verde floresta | #16a34a | #f0fdf4 | #fbbf24 |
| Azul oceano | #0891b2 | #ecfeff | #f472b6 |
deployer-pages.ymlname: Deployer sur GitHub Pages # nom qui apparait dans l'UI ActionsEste nome é puramente cosmético — ajuda a reconhecer o workflow no separador Actions do repositório.
on:
push:
branches: [main]
workflow_dispatch:Dois acionadores:
main (o caso normal).permissions:
contents: read
pages: write
id-token: writeO trio mágico do Pages. Sem estas três linhas, obtém-se Resource not accessible by integration no job deployer (é exatamente a avaria 1 da missão 3):
contents: read — permite a actions/checkout@v4 ler o código.pages: write — autoriza actions/deploy-pages@v4 a publicar.id-token: write — necessário para a autenticação OIDC entre o runner e o serviço Pages.concurrency:
group: pages
cancel-in-progress: falseSe dois git push chegarem quase ao mesmo tempo, o GitHub Actions não lança duas implantações em paralelo no mesmo grupo pages — os runs executam-se um a seguir ao outro. cancel-in-progress: false = deixa-se o run em curso terminar antes de arrancar o seguinte. É crucial para o Pages: duas publicações simultâneas produzem estados incoerentes.
jobs:
construire:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # 1. recuperer le code
- uses: actions/setup-python@v5 # 2. installer Python
with:
python-version: "3.12"
- run: python outils/build.py # 3. generer dist/
- uses: actions/upload-pages-artifact@v3 # 4. preparer l'artefact
with:
path: dist # <-- IMPORTANT : dossier a publierQuatro etapas sequenciais. Se uma falhar, as seguintes não se executam.
deployer:
needs: construire # attend que "construire" reussisse
environment:
name: github-pages # environnement officiel Pages
url: ${{ steps.publication.outputs.page_url }} # affiche l'URL dans l'UI
steps:
- uses: actions/deploy-pages@v4
id: publicationO job deployer espera explicitamente por construire graças a needs:. No fim, a UI GitHub mostra um ligação clicável para https://<vous>.github.io/<depot>/.
verifier-config.ymlon:
pull_request:
branches: [main]
push:
branches-ignore: [main]Aciona-se em PR para main e em push para qualquer ramo exceto main. O objetivo: validar antes de o código ser fundido. Note que se exclui main do push: — senão duplicaria o trabalho com deployer-pages.yml.
O resto das etapas é idêntico a deployer-pages.yml exceto que não se publica: limita-se a verificar que dist/ se gera sem erro.
Sequência a reproduzir duas vezes:
# --- Iteration 1 : fond violet ---
# Edite site/config.json : "couleur_fond": "#7c3aed"
git add site/config.json
git commit -m "fond violet"
git push
# Attendre ~40 s -> ouvrir https://<vous>.github.io/<depot>/ -> fond violet
# --- Iteration 2 : fond rouge ---
# Edite site/config.json : "couleur_fond": "#dc2626"
git add site/config.json
git commit -m "fond rouge"
git push
# Attendre ~40 s -> ouvrir la meme URL -> fond rougeVerificações a incluir no relatório:
git log --oneline: mostra os 2 commits com os respetivos SHAs curtos.Deployer sur GitHub Pages estão verdes.Diff da correção em .github/workflows/casse-1-permissions-manquantes.yml:
name: Casse 1 - Permissions manquantes
on:
push:
branches: [main]
workflow_dispatch:
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
concurrency:
group: pages
cancel-in-progress: false
jobs:
...Diagnóstico escrito a colocar no relatório:
Sem o bloco permissions:, o GitHub concede ao workflow apenas contents: read (leitura do código) — não a permissão de publicar no Pages. A action actions/deploy-pages@v4 exige explicitamente pages: write e id-token: write (token OIDC). Daí o erro Resource not accessible by integration (403 Forbidden) no job deployer.
Regra de segurança: dá-se o mínimo de permissões possível, mas não menos. O princípio do menor privilégio aplicado ao CI/CD.
Diff da correção:
name: Casse 2 - Declencheur errone
on:
- pushh:
+ push:
branches: [main]Diagnóstico escrito a colocar no relatório:
O GitHub Actions não assinala os acionadores desconhecidos em on: — ignora-os em silêncio. Um simples pushh (com dois h) faz com que nenhum run seja acionado: não se vê erro, não se vê nada de nada no separador Actions.
Como se descobre a avaria? Faz-se push de um commit, vai-se a Actions, constata-se que nenhum run aparece para este workflow. O único indício é a ausência.
Truque antiarmadilha: um Run workflow rápido (botão manual, disponível se workflow_dispatch: estiver presente) verifica que o próprio workflow é sintaticamente válido. O workflow_dispatch: funciona independentemente de push:.
Diff da correção:
- name: Preparer le dossier a publier
uses: actions/upload-pages-artifact@v3
with:
- path: public
+ path: distDiagnóstico escrito a colocar no relatório:
outils/build.py escreve sistematicamente em dist/ (constante DIST = RACINE / "dist" no código Python). O workflow pedia path: public — uma pasta que não existe. Daí:
Error: Path does not exist: ./publicactions/upload-pages-artifact@v3 verifica a existência da pasta antes de criar o artefacto e falha imediatamente se o caminho estiver errado. A boa prática: fazer sempre apontar o workflow para a pasta exata que o script de build produz.
README.mdNo README.md do seu repositório GitHub (na raiz, não na pasta projet14-github-actions-pages-tp/ do curso), acrescente:
# Mon site portfolio

Site publie : https://<vous>.github.io/<depot>/O badge fica verde se o último run passou, vermelho caso contrário. Atualiza-se sozinho.
config.json inválidogit checkout -b test-config-cassee
# Editer site/config.json et remplacer "couleur_fond": "#0f172a" par "couleur_fond": "rouge"
git add site/config.json
git commit -m "test : couleur invalide"
git push -u origin test-config-cassee
# Puis sur GitHub : ouvrir une PR de test-config-cassee vers mainO workflow Verifier la configuration vai acionar-se, build.py vai protestar:
ERREUR : couleur_fond doit etre au format #RRGGBB (recu : 'rouge')A PR mostra um quadrado vermelho e o botão Merge pull request fica bloqueado se configurou a proteção de ramo (Settings → Branches → Add rule → Require status checks to pass).
.github/workflows/notifier.yml:
name: Notifier une URL
on:
workflow_dispatch:
jobs:
notifier:
runs-on: ubuntu-latest
steps:
- name: Ping du webhook
env:
URL: ${{ secrets.URL_WEBHOOK }}
run: |
curl -X POST "$URL" \
-H "Content-Type: application/json" \
-d '{"texte":"Un utilisateur a declenche notifier.yml"}'O secret URL_WEBHOOK define-se em Settings → Secrets and variables → Actions → New repository secret. Nunca aparecerá nos logs: o GitHub mascara automaticamente qualquer valor que corresponda a um secret.
1. on: push sem branches: — quando é acionado?
É acionado em cada push em todos os ramos. Raramente é desejável: um git push num ramo de feature em desenvolvimento lança uma implantação Pages em produção. Limite sempre com branches: [main] ou uma lista explícita.
2. Por que id-token: write é necessário para o Pages? Para que serve o token OIDC?
actions/deploy-pages@v4 usa OIDC (OpenID Connect) para provar ao serviço Pages que o pedido vem mesmo de um run GitHub Actions autorizado, sem usar palavra-passe nem PAT (Personal Access Token). O token OIDC é efémero (duração de vida limitada ao run) e assinado pelo GitHub — mais seguro do que um secret estático. id-token: write autoriza o runner a gerar este token para este workflow.
3. Dois pushes simultâneos em main — o que faz concurrency?
Sem concurrency, o GitHub lança dois workflows em paralelo. O primeiro termina o upload do artefacto, o segundo arranca o seu próprio upload, e o Pages pode receber as duas publicações fora de ordem → a ordem final deixa de estar garantida. Com concurrency: { group: pages, cancel-in-progress: false }, os dois runs são serializados: o segundo espera que o primeiro termine. cancel-in-progress: true teria outro efeito — cancelar o run em curso assim que um novo arranca, útil para um rebuild ultrarrápido mas perigoso para o Pages.
4. Um secret pode aparecer nos logs?
O GitHub mascara automaticamente qualquer valor registado como secret: aparece sob a forma de *** nos logs. Mas se transformar o secret (por exemplo echo "$SECRET" | base64), o mascaramento já não se aplica ao valor transformado. Regra: nunca transformar um secret num run:, usá-lo tal qual via env: e passá-lo diretamente à ferramenta (aqui curl).
5. Por que manter os dois workflows deployer-pages.yml e verifier-config.yml?
deployer-pages.yml publica em main: é o workflow de entrega. Só corre depois de um merge.verifier-config.yml valida nos ramos de feature e nas PR: é o workflow de prevenção. Impede que um config.json partido chegue a main.Os dois formam uma rede de duas camadas: a verificação bloqueia a montante, a implantação entrega a jusante. É o padrão CI (Continuous Integration) + CD (Continuous Deployment).
6. O que aconteceria se build.py criasse um ficheiro historique.log?
Nada de duradouro. O runner é uma VM efémera destruída no fim do run. O ficheiro desapareceria com a VM. Para conservar um histórico entre runs, seria preciso commitá-lo no repositório (mau, polui o repo), guardá-lo num artefacto com actions/upload-artifact (duração de vida 90 dias no máximo), ou enviá-lo para um serviço externo (S3, Postgres, etc.).
| Sintoma | Causa provável | Solução |
|---|---|---|
Resource not accessible by integration | Bloco permissions: ausente ou incompleto | Acrescentar pages: write + id-token: write |
| Nenhum run é acionado | Erro de digitação em on: (pushh:, pull_requests:) | Verificar a ortografia das chaves YAML |
Path does not exist: ./xxx | Caminho em upload-pages-artifact.path: não corresponde à pasta de saída de build.py | Verificar path: = dist |
| A página publicada mostra o conteúdo antigo | Cache do navegador | Ctrl+Shift+R para um recarregamento forçado |
| A primeira implantação demora > 5 min | Propagação DNS do GitHub Pages | Normal na primeira vez, ~40 s depois |
Workflow vermelho na etapa python outils/build.py | config.json inválido | Lançar python .\outils\build.py em local para ver o erro exato |
| O workflow corre mas o URL devolve 404 | Source Pages ainda em modo «Deploy from a branch» | Passar para GitHub Actions em Settings → Pages |
| Dois runs Pages ao mesmo tempo produzem conteúdo incoerente | concurrency: ausente | Acrescentar o bloco concurrency: { group: pages } |
O professor abre três separadores:
config.json, presença de .github/workflows/ com pelo menos os 3 workflows corrigidos (os originais deployer-pages.yml e verifier-config.yml + as 3 avarias reparadas).Deployer sur GitHub Pages (missão 2), mais os runs da missão 3 (antes/depois da reparação).https://<vous>.github.io/<votre-depot>/ — deve mostrar-se com as suas cores personalizadas e um SHA recente.Depois lê o seu RAPPORT.md:
Um relatório limpo + um repositório bem estruturado = nota máxima fácil. A dificuldade não é técnica, está na rigor da demonstração.
Curso criado pelo Dr. Haythem REHOUMA — Desenvolvimento e implantação de soluções de dados