name: CI and Deploy to Raspberry Pi on: push: branches: - production - dev - preview paths: - 'app/**' - 'public/**' - 'styles/**' - 'Dockerfile' - 'docker-compose.yml' - '.github/workflows/main.yml' - 'next.config.ts' - 'package.json' - 'package-lock.json' - 'tsconfig.json' - 'tailwind.config.ts' jobs: test_and_build: runs-on: ubuntu-latest steps: - name: Check Out Code uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: node-version: '22' - name: Cache Node.js modules uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: Create env file run: | touch .env echo "NEXT_PUBLIC_BASE_URL=${{ vars.NEXT_PUBLIC_BASE_URL }}" >> .env echo "NEXT_PUBLIC_GHOST_API_URL=${{ vars.NEXT_PUBLIC_GHOST_API_URL }}" >> .env echo "NEXT_PUBLIC_GHOST_API_KEY=${{ secrets.NEXT_PUBLIC_GHOST_API_KEY }}" >> .env echo "NEXT_PUBLIC_MY_EMAIL=${{ vars.NEXT_PUBLIC_MY_EMAIL }}" >> .env echo "NEXT_PUBLIC_MY_PASSWORD=${{ secrets.NEXT_PUBLIC_MY_PASSWORD }}" >> .env cat .env - name: Show folder structure run: | ls -la - name: Install Dependencies run: npm install - name: Run Tests run: npm run test - name: Log in to GHCR run: | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin - name: Build and Push Multi-Arch Docker Image run: | IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/my-nextjs-app:${{ github.ref_name }}" docker buildx create --use docker buildx build \ --platform linux/arm64 \ -t "$IMAGE_NAME" \ --push \ . deploy: runs-on: self-hosted needs: test_and_build steps: - name: Check Out Code uses: actions/checkout@v4 - name: Set Environment Variables run: | if [[ "${{ github.ref_name }}" == "production" ]]; then echo "DEPLOY_ENV=production" >> $GITHUB_ENV echo "PORT=4000" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "dev" ]]; then echo "DEPLOY_ENV=dev" >> $GITHUB_ENV echo "PORT=4001" >> $GITHUB_ENV elif [[ "${{ github.ref_name }}" == "preview" ]]; then echo "DEPLOY_ENV=preview" >> $GITHUB_ENV echo "PORT=4002" >> $GITHUB_ENV fi - name: Log in to GHCR run: | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin - name: Pull Docker Image run: | IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/my-nextjs-app:${{ github.ref_name }}" IMAGE_NAME=$(echo "$IMAGE_NAME" | tr '[:upper:]' '[:lower:]') docker pull "$IMAGE_NAME" - name: Deploy on Raspberry Pi (Zero-Downtime) run: | IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/my-nextjs-app:${{ github.ref_name }}" IMAGE_NAME=$(echo "$IMAGE_NAME" | tr '[:upper:]' '[:lower:]') CONTAINER_NAME="nextjs-$DEPLOY_ENV" NEW_CONTAINER_NAME="$CONTAINER_NAME-new" # Remove existing temporary container, if any if [ "$(docker ps -aq -f name=$NEW_CONTAINER_NAME)" ]; then docker rm -f "$NEW_CONTAINER_NAME" || true fi echo "Deploying $CONTAINER_NAME with $IMAGE_NAME" # Start new container on a temporary internal port docker run -d --name "$NEW_CONTAINER_NAME" --network big-bear-ghost_ghost-network -p 40000:3000 \ "$IMAGE_NAME" # Wait for the new container to start sleep 10 # Debugging: Check if the environment variables are set correctly docker exec "$NEW_CONTAINER_NAME" printenv if [ "$(docker inspect --format='{{.State.Running}}' "$NEW_CONTAINER_NAME")" = "true" ]; then # Stop/remove the old container if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then docker stop "$CONTAINER_NAME" || true docker rm "$CONTAINER_NAME" || true fi # Replace the new container with final name/port docker stop "$NEW_CONTAINER_NAME" || true docker rm "$NEW_CONTAINER_NAME" || true docker run -d --name "$CONTAINER_NAME" --network big-bear-ghost_ghost-network -p $PORT:3000 \ "$IMAGE_NAME" else echo "New container failed to start." docker logs "$NEW_CONTAINER_NAME" exit 1 fi