Aller au contenu principal

GitHub Actions : architecture CI/CD réutilisable

· 3 minutes de lecture

Quand plusieurs dépôts partagent la même stack technique, chacun maintient souvent une copie quasi-identique de ses workflows CI/CD. Une modification — nouvelle version d'un outil, changement de runner, ajout d'une étape de sécurité — doit être répercutée manuellement dans chaque dépôt. Un dépôt centralisé de workflows mutualisés résout ce problème : les dépôts consommateurs appellent les workflows du dépôt central, qui devient le seul point de maintenance.

Architecture

Le dépôt shared_workflows contient :

  • des workflows réutilisables (workflow_call) qui constituent les points d'entrée pour les dépôts consommateurs
  • des actions composites qui factorisent la logique commune entre ces workflows
  • des appels à des workflows génériques (pre-commit, lint) partagés entre toutes les stacks

Les dépôts consommateurs ont un workflow minimal qui délègue tout au dépôt central.

Workflow réutilisable dans le dépôt central

Un workflow réutilisable se déclare avec on: workflow_call. Il expose des inputs et des secrets que les appelants doivent fournir :

# shared_workflows/.github/workflows/build.yml
name: Build and Test

on:
workflow_call:
inputs:
image-name:
description: "Docker image name"
required: true
type: string
python-version:
description: "Python version"
required: false
type: string
default: "3.12"
secrets:
registry-token:
required: true
description: "Token for container registry"

jobs:
pre-commit:
uses: org/generic_workflows/.github/workflows/pre-commit.yml@main

build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]
container:
image: python:${{ matrix.python-version }}-slim
steps:
- uses: actions/checkout@v4

- name: Build and push image
uses: org/shared_workflows/.github/actions/docker-build@main
with:
image: ${{ inputs.image-name }}
tag: ${{ github.sha }}
registry-token: ${{ secrets.registry-token }}

Workflow consommateur dans chaque dépôt

Le workflow de chaque dépôt consommateur devient minimal — il se contente d'appeler le workflow central :

# project_a/.github/workflows/ci.yml
name: CI

on:
push:

jobs:
build:
uses: org/shared_workflows/.github/workflows/build.yml@main
with:
image-name: ghcr.io/org/project-a
secrets:
registry-token: ${{ secrets.GITHUB_TOKEN }}

Un changement dans shared_workflows/build.yml s'applique immédiatement à tous les dépôts sans aucune modification de leur côté.

Action composite dans le dépôt central

Les actions composites factorisent la logique commune entre les workflows du dépôt central lui-même :

# shared_workflows/.github/actions/docker-build/action.yml
name: "Docker Build and Push"
description: "Build a Docker image and push it to GHCR"

inputs:
image:
required: true
tag:
required: true
registry-token:
required: true

runs:
using: "composite"
steps:
- uses: docker/setup-buildx-action@v3

- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ inputs.registry-token }}

- uses: docker/build-push-action@v5
with:
push: true
tags: ${{ inputs.image }}:${{ inputs.tag }}
cache-from: type=gha
cache-to: type=gha,mode=max

Différence entre action et workflow réutilisable

Les deux mécanismes se complètent mais ont des périmètres différents :

Action compositeWorkflow réutilisable
Appelé depuisUne step (uses)Un job (uses)
EnvironnementHérite du job appelantDéfinit ses propres runners
SecretsVia inputsVia secrets dédié
UsageFactoriser des stepsEncapsuler un pipeline complet

Un workflow réutilisable définit on: workflow_call et ne peut pas être utilisé dans une step — il est un job à part entière avec ses propres runners. Une action composite s'exécute dans l'environnement du job qui l'appelle et peut être insérée n'importe où dans une liste de steps.