# Deploy from GitHub Actions

Deploy main to production and create a complete preview for each pull request.

Canonical: https://docs.deliberate.space/deploy/github-actions/

Use this workflow to build one immutable image for each commit. A pull request
into `main` applies it to `preview-pr-<number>`; a push to `main` applies it to
production. Closing the pull request deletes its complete preview Environment.

The workflow does not create preview infrastructure procedurally. The first
`apply` to a name matching the Project Flow's `preview-*` stage forks the
configured parent Environment, then reconciles the proposed image on top.

## 1. Add deployment credentials

Create a Team-scoped API token under **API tokens** in the console and add it to
the GitHub repository as the `DELIBERATE_TOKEN` Actions secret. Add the Team
slug as the `DELIBERATE_TEAM` repository variable.

The example assumes the directly-authored Component is named `app` and its
image belongs at `registry.deliberate.cloud/<team>/app`. Change both names to
match the Project.

## 2. Add the workflow

Create `.github/workflows/deliberate.yaml`:

```yaml
name: deliberate

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened, closed]

permissions:
  contents: read

env:
  DELIBERATE_TOKEN: ${{ secrets.DELIBERATE_TOKEN }}
  DELIBERATE_TEAM: ${{ vars.DELIBERATE_TEAM }}

jobs:
  deploy:
    if: >-
      github.event_name == 'push' ||
      (github.event.action != 'closed' &&
       github.event.pull_request.head.repo.full_name == github.repository)
    runs-on: ubuntu-latest
    concurrency:
      group: deliberate-${{ github.event.pull_request.number || 'production' }}
      cancel-in-progress: true
    steps:
      - uses: actions/checkout@v4

      - name: Install deliberate
        run: curl -fsSL https://get.deliberate.cloud | sh

      - name: Log Docker into the deliberate registry
        run: >-
          deliberate registry login
          --runtime docker
          --team "$DELIBERATE_TEAM"
          --name "github-${GITHUB_RUN_ID}"
          --days 1

      - name: Build and push the immutable image
        id: image
        run: |
          IMAGE="registry.deliberate.cloud/${DELIBERATE_TEAM}/app:git-${GITHUB_SHA}"
          docker build --tag "$IMAGE" .
          docker push "$IMAGE"
          echo "reference=$IMAGE" >> "$GITHUB_OUTPUT"

      - name: Select Environment
        id: environment
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          if [ "$GITHUB_EVENT_NAME" = "push" ]; then
            echo "name=production" >> "$GITHUB_OUTPUT"
          else
            echo "name=preview-pr-${PR_NUMBER}" >> "$GITHUB_OUTPUT"
          fi

      - name: Apply
        run: >-
          deliberate apply
          --env "${{ steps.environment.outputs.name }}"
          --image "app=${{ steps.image.outputs.reference }}"
          --yes

      - name: Wait for readiness
        run: >-
          deliberate envs status
          "${{ steps.environment.outputs.name }}"
          --wait
          --timeout 10m

      - name: Report the application URL
        run: |
          URL="$(deliberate open --env "${{ steps.environment.outputs.name }}" --print)"
          echo "### deliberate. deployment" >> "$GITHUB_STEP_SUMMARY"
          echo "$URL" >> "$GITHUB_STEP_SUMMARY"

  remove-preview:
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    concurrency:
      group: deliberate-${{ github.event.pull_request.number }}
      cancel-in-progress: true
    steps:
      - uses: actions/checkout@v4

      - name: Install deliberate
        run: curl -fsSL https://get.deliberate.cloud | sh

      - name: Remove the complete preview Environment
        run: >-
          deliberate envs delete
          "preview-pr-${{ github.event.pull_request.number }}"
          --force
```

The `--image` override changes the selected Component image for this apply
without editing the checked-out file. The resolved image is stored in the
Environment revision, so deployment history, rollback, reconciliation, and
`deliberate pull` all show the image that actually ran.

Pull requests from forks do not receive repository secrets and are excluded by
the deploy condition above. Review and run untrusted contributions without
granting them a Team deployment token.

## Next steps

- [Understand preview Environment behavior](/deploy/environments/)
- [Inspect and recover a failed deployment](/operate/observe-and-recover/)
- [Review the CLI commands used by the workflow](/reference/cli/)
