name: Build & Deploy on: workflow_dispatch: push: branches: [main] pull_request: branches: [main] jobs: # Job 1: Build the Docker image build: runs-on: ubuntu-latest outputs: repo: ${{ steps.meta.outputs.REPO }} repo-name: ${{ steps.meta.outputs.REPO_NAME_ONLY }} repo-path: ${{ steps.meta.outputs.REPO_PROJECT_PATH }} image-tar: ${{ steps.meta.outputs.REPO_NAME_ONLY }}-${{ github.ref_name }}_${{ github.sha }}.tar tags: ${{ steps.generated_docker_tags.outputs.tag }} prod: ${{ steps.meta.outputs.prod }} steps: - name: Checkout the repo uses: actions/checkout@v4 - name: Ensure scripts are executable run: chmod +x scripts/*.sh - name: Setup build metadata and environment id: meta run: | echo "✅ Exit script on any error" set -eu -o pipefail # Parse repository name and set outputs eval "$(./scripts/parse-repository-name.sh '${{ github.repository }}')" echo "REPO=$REPO" >> $GITHUB_OUTPUT echo "REPO_NAME_ONLY=$REPO_NAME_ONLY" >> $GITHUB_OUTPUT echo "REPO_PROJECT_PATH=$REPO_PROJECT_PATH" >> $GITHUB_OUTPUT # Determine PROD environment prod_value="" echo "🔍 Check if PROD is set via vars; if not, determine from github.ref" if [ -z "${{ vars.PROD }}" ]; then prod_value="${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-prerelease') }}" echo "📦 PROD mode unset, determined from github.ref (starts with v and does not end with -prerelease?): ${prod_value}" else prod_value="${{ vars.PROD }}" echo "📦 PROD mode already set to: ${prod_value}" fi echo "prod=${prod_value}" >> $GITHUB_OUTPUT # Set environment variables for subsequent steps echo "🖊️ Writing determined values to GITHUB_ENV:" echo "PROD=${prod_value}" >> $GITHUB_ENV echo "PROD=${prod_value} -> GITHUB_ENV" echo "IMAGE_TAR_NAME=${REPO_NAME_ONLY}-${{ github.ref_name }}_${{ github.sha }}.tar" >> $GITHUB_ENV echo "IMAGE_TAR_NAME=${REPO_NAME_ONLY}-${{ github.ref_name }}_${{ github.sha }}.tar -> GITHUB_ENV" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Generate tags id: generated_docker_tags run: | echo "✅ Exit script on any error" set -eu -o pipefail # Use the script to generate tags TAG_LIST=$(./scripts/generate-docker-tags.sh \ "${{ steps.meta.outputs.REPO }}" \ "${{ github.sha }}" \ "${{ github.ref }}" \ "$PROD") echo "Final list of generated tags:" echo "$TAG_LIST" TAG_COUNT=$(echo "$TAG_LIST" | wc -l) if [[ -z "${{ github.sha }}" || $TAG_COUNT -lt 4 ]]; then echo "⚠️ No tags (or too few) were generated based on the logic. Need at least 4 tags. Generated: $TAG_COUNT" exit 1 fi # Output the tags for the docker build action { echo "tag<> "$GITHUB_OUTPUT" - name: Run prebuild tasks run: ./scripts/prebuild.sh - name: Cache Docker layers uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} restore-keys: | ${{ runner.os }}-buildx- - name: Extract version for Docker build id: extract_version run: | pip install setuptools-scm VERSION=$(python -c "from setuptools_scm import get_version; print(get_version())") echo "VERSION=${VERSION}" >> $GITHUB_ENV - name: Build container uses: docker/build-push-action@v6 with: outputs: type=docker,dest=${{ runner.temp }}/${{ steps.meta.outputs.REPO_NAME_ONLY }}-${{ github.ref_name }}_${{ github.sha }}.tar tags: ${{ steps.generated_docker_tags.outputs.tag }} build-args: | VERSION=${{ env.VERSION }} context: . cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max - name: Rotate cache run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache - name: Upload container as artifact uses: actions/upload-artifact@v4 with: name: ${{ env.IMAGE_TAR_NAME }} path: ${{ runner.temp }}/${{ steps.meta.outputs.REPO_NAME_ONLY }}-${{ github.ref_name }}_${{ github.sha }}.tar if-no-files-found: error retention-days: 1 # Job 2: Deploy (only runs on main branch or tags) deploy: needs: build runs-on: ubuntu-latest if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) # Determine environment based on ref environment: ${{ (startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-prerelease')) && 'production' || 'staging' }} steps: - name: Checkout the repo uses: actions/checkout@v4 - name: Ensure scripts are executable run: chmod +x scripts/*.sh - name: Setup deployment metadata and environment id: meta run: | echo "✅ Exit script on any error" set -eu -o pipefail # Parse repository name and set outputs eval "$(./scripts/parse-repository-name.sh '${{ github.repository }}')" echo "REPO=$REPO" >> $GITHUB_OUTPUT echo "REPO_NAME_ONLY=$REPO_NAME_ONLY" >> $GITHUB_OUTPUT echo "REPO_PROJECT_PATH=$REPO_PROJECT_PATH" >> $GITHUB_OUTPUT # Determine PROD environment prod_value="" echo "🔍 Check if PROD is set via vars; if not, determine from github.ref" if [ -z "${{ vars.PROD }}" ]; then prod_value="${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-prerelease') }}" echo "📦 PROD mode unset, determined from github.ref (starts with v and does not end with -prerelease?): ${prod_value}" else prod_value="${{ vars.PROD }}" echo "📦 PROD mode already set to: ${prod_value}" fi echo "prod=${prod_value}" >> $GITHUB_OUTPUT # Set all deployment environment variables echo "📝 Setting deployment environment variables" echo "REPO_PROJECT_PATH=${REPO_PROJECT_PATH}" >> $GITHUB_ENV echo "REPO_NAME_ONLY=${REPO_NAME_ONLY}" >> $GITHUB_ENV echo "IMAGE_TAR_NAME=${REPO_NAME_ONLY}-${{ github.ref_name }}_${{ github.sha }}.tar" >> $GITHUB_ENV echo "PROD=${prod_value}" >> $GITHUB_ENV - name: Download container artifact uses: actions/download-artifact@v4 with: name: ${{ env.IMAGE_TAR_NAME }} path: ${{ runner.temp }} - name: Get Deploy Secrets uses: bitwarden/sm-action@v2 with: access_token: ${{ secrets.BW_ACCESS_TOKEN }} secrets: | 27a8da8d-5fb4-4f58-baaf-b2dd0032eca8 > DEPLOY_HOST 4cf9ab8d-1772-4ab0-9219-b2dd003315d4 > DEPLOY_KEY 9aefe34e-c2cf-442e-973c-b2dd0032b6cf > ENV_FILE_BASE64 d3bb47f8-bfc0-4a61-9cee-b2df0147a02a > CF_PEM_CERT 5f658ddf-aadd-4464-b501-b2df0147c338 > CF_PEM_CA - name: Set up SSH run: | mkdir -p $HOME/.ssh echo -e "${DEPLOY_KEY}" > $HOME/.ssh/deploy.key chmod 700 $HOME/.ssh chmod 600 $HOME/.ssh/deploy.key cat >>$HOME/.ssh/config <