# Lint and test, build and push an image, then deploy that exact tag. # # This is the shape the action exists for: Dokploy's own Git webhook fires on # every push, before anything has been checked. Here the deploy is one more # job, gated behind the ones that can fail cheaply. name: deploy on: push: branches: [main] # One deployment at a time. Do not cancel a run mid-deploy -- the build would # keep going on the Dokploy side with nobody watching it. concurrency: group: deploy-${{ github.ref }} cancel-in-progress: false jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "20" cache: npm - run: npm ci - run: npm run lint - run: npm test build: needs: check runs-on: ubuntu-latest permissions: contents: read packages: write outputs: image: ${{ steps.meta.outputs.image }} steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # A digest or a commit-pinned tag, never `latest`: the deploy has to be # able to name the exact artifact the tests passed against. - id: meta run: echo "image=ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" - uses: docker/build-push-action@v6 with: context: . push: true tags: ${{ steps.meta.outputs.image }} cache-from: type=gha cache-to: type=gha,mode=max deploy: needs: build runs-on: ubuntu-latest environment: production steps: - uses: maxvojtkov/dokploy-deploy-action@v1 with: host: ${{ secrets.DOKPLOY_HOST }} api-key: ${{ secrets.DOKPLOY_API_KEY }} project: shop service: api docker-image: ${{ needs.build.outputs.image }} registry-url: ghcr.io registry-username: ${{ github.actor }} # GITHUB_TOKEN expires with this job. Dokploy stores these credentials # and reuses them whenever it restarts the container, so use a # long-lived PAT -- or a Dokploy registry -- for a private image. registry-password: ${{ secrets.GHCR_PULL_TOKEN }} timeout: 900