name: Deploy on: workflow_dispatch: inputs: env: description: "Environnement cible" required: true type: choice options: - staging - prod default: staging version: description: "Tag explicite vX.Y.Z (utilisé pour prod, sinon dernier tag existant)" required: false default: "" env: REGISTRY: ${{ secrets.DOCKER_REGISTRY || 'registry.local' }} IMAGE_NAME: ${{ secrets.DOCKER_IMAGE || 'mon-projet' }} PROJECT_ROOT: /opt/mon-projet jobs: prepare: name: Prepare version and sources runs-on: docker outputs: version: ${{ steps.resolve_version.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Fetch tags run: git fetch --tags --force - name: Resolve target version id: resolve_version shell: bash run: | set -euo pipefail explicit="${{ inputs.version }}" if [ -n "$explicit" ]; then echo "version=$explicit" >> "$GITHUB_OUTPUT" exit 0 fi tag=$(git describe --tags --abbrev=0 2>/dev/null || true) if [ -z "$tag" ]; then echo "No tag found and no version provided." >&2 exit 1 fi echo "version=$tag" >> "$GITHUB_OUTPUT" - name: Sync repo to /opt/mon-projet run: | mkdir -p "${PROJECT_ROOT}" cp -a . "${PROJECT_ROOT}/" build: name: Build images (latest + versioned) runs-on: docker needs: prepare env: DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} VERSION_TAG: ${{ needs.prepare.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 - name: Docker login if: env.DOCKER_USER != '' && env.DOCKER_PASSWORD != '' run: | echo "${DOCKER_PASSWORD}" | docker login "${REGISTRY}" -u "${DOCKER_USER}" --password-stdin - name: Build latest run: docker build -t "${REGISTRY}/${IMAGE_NAME}:latest" -f Dockerfile . - name: Build versioned run: docker build -t "${REGISTRY}/${IMAGE_NAME}:${VERSION_TAG}" -f Dockerfile . - name: Push images run: | docker push "${REGISTRY}/${IMAGE_NAME}:latest" docker push "${REGISTRY}/${IMAGE_NAME}:${VERSION_TAG}" deploy-staging: name: Deploy to staging runs-on: docker needs: build if: inputs.env == 'staging' env: ENV_DIR: ${{ env.PROJECT_ROOT }}/env/staging DOTENV: ${{ env.PROJECT_ROOT }}/env/staging/.env steps: - name: List synced sources run: ls -la "${PROJECT_ROOT}" - name: Generate staging .env from secret env: STAGING_ENV: ${{ secrets.STAGING_ENV_VARS }} run: | mkdir -p "${ENV_DIR}" echo "${STAGING_ENV}" > "${DOTENV}" - name: Deploy with docker compose working-directory: ${{ env.PROJECT_ROOT }} run: | docker compose -f docker-compose.staging.yml --env-file "${DOTENV}" pull docker compose -f docker-compose.staging.yml --env-file "${DOTENV}" up -d deploy-prod: name: Deploy to prod runs-on: docker needs: build if: inputs.env == 'prod' env: ENV_DIR: ${{ env.PROJECT_ROOT }}/env/prod DOTENV: ${{ env.PROJECT_ROOT }}/env/prod/.env VERSION_TAG: ${{ needs.prepare.outputs.version }} steps: - name: Check target version run: echo "Deploying prod with ${VERSION_TAG}" - name: Generate prod .env from secret env: PROD_ENV: ${{ secrets.PROD_ENV_VARS }} run: | mkdir -p "${ENV_DIR}" echo "${PROD_ENV}" > "${DOTENV}" - name: Deploy with docker compose working-directory: ${{ env.PROJECT_ROOT }} env: IMAGE_TAG: ${{ env.VERSION_TAG }} run: | docker compose -f docker-compose.prod.yml --env-file "${DOTENV}" pull docker compose -f docker-compose.prod.yml --env-file "${DOTENV}" up -d