name: Deploy to Production on: workflow_dispatch: inputs: image_tag: description: 'Image tag to deploy (e.g. v1.2.3, or "latest")' required: true default: 'latest' jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy via SSH uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2 # v1.2.5 env: # Pass the user-supplied tag as an env var (not interpolated into the # remote script body). The remote script runs as the deploy user, which # has docker access == root on prod, so the tag is validated before use. IMAGE_TAG: ${{ inputs.image_tag }} with: host: ${{ secrets.PROD_SSH_HOST }} username: ${{ secrets.PROD_SSH_USER }} key: ${{ secrets.PROD_SSH_KEY }} envs: IMAGE_TAG script: | set -eu case "$IMAGE_TAG" in latest|v[0-9]*) : ;; *) echo "Refusing to deploy invalid tag: $IMAGE_TAG" >&2; exit 1 ;; esac IMAGE="gitea.stwaddle.com/stwaddle/budget" cd /srv/stwaddlecom docker pull "${IMAGE}:${IMAGE_TAG}" # Re-tag as :latest so the compose definition (which references :latest) picks it up. docker tag "${IMAGE}:${IMAGE_TAG}" "${IMAGE}:latest" docker compose up -d budget