The DeployHQ CLI works seamlessly in CI/CD pipelines. Authentication uses environment variables, so no interactive login is needed.

## Setup

### 1. Set Secrets

Add these secrets to your CI provider:

| Secret | Description |
|--------|-------------|
| `DEPLOYHQ_ACCOUNT` | Your account subdomain (e.g. `mycompany`) |
| `DEPLOYHQ_EMAIL` | API user email |
| `DEPLOYHQ_API_KEY` | API key (found in Settings > Security) |

### 2. Install the CLI

Use the install script in your pipeline:

```bash
curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
```

### 3. Deploy

```bash
dhq deploy --server production --revision $COMMIT_SHA --wait --json
```

The `--wait` flag blocks until the deployment finishes, and `--json` provides machine-readable output for parsing results.

## GitHub Actions Examples

### Basic Deployment

Deploy to production on push to main:

```yaml
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

env:
  DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
  DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
  DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
  DEPLOYHQ_PROJECT: my-app

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Install DeployHQ CLI
        run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh

      - name: Deploy to production
        run: dhq deploy --server production --revision ${{ github.sha }} --wait --json

      - name: Show deployment logs (on failure)
        if: failure()
        run: |
          DEP_ID=$(dhq deployments list --json | jq -r '.data.records[0].identifier')
          dhq deployments logs "$DEP_ID"
```

### Multi-Environment Deployment

Deploy to staging on push, production on release, with auto-rollback:

```yaml
# .github/workflows/deploy-multi-env.yml
name: Deploy (multi-environment)

on:
  push:
    branches: [main]
  release:
    types: [published]

env:
  DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
  DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
  DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
  DEPLOYHQ_PROJECT: my-app

jobs:
  deploy-staging:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Install DeployHQ CLI
        run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh

      - name: Deploy to staging
        run: dhq deploy --server staging --revision ${{ github.sha }} --wait --json

  deploy-production:
    if: github.event_name == 'release'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Install DeployHQ CLI
        run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh

      - name: Deploy to production
        run: dhq deploy --server production --revision ${{ github.sha }} --wait --json

      - name: Rollback on failure
        if: failure()
        run: |
          PREV=$(dhq deployments list --json | jq -r '.data.records[1].identifier')
          dhq rollback "$PREV" --json
```

### Deploy on PR Merge with Status Comment

Deploy when a PR is merged, then post a deployment summary as a PR comment:

```yaml
# .github/workflows/deploy-on-pr-merge.yml
name: Deploy on PR merge

on:
  pull_request:
    types: [closed]
    branches: [main]

env:
  DEPLOYHQ_ACCOUNT: ${{ secrets.DEPLOYHQ_ACCOUNT }}
  DEPLOYHQ_EMAIL: ${{ secrets.DEPLOYHQ_EMAIL }}
  DEPLOYHQ_API_KEY: ${{ secrets.DEPLOYHQ_API_KEY }}
  DEPLOYHQ_PROJECT: my-app

jobs:
  deploy:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: Install DeployHQ CLI
        run: curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh

      - name: Deploy and wait
        id: deploy
        run: |
          RESULT=$(dhq deploy \
            --server production \
            --revision ${{ github.event.pull_request.merge_commit_sha }} \
            --wait --json)
          DEP_ID=$(echo "$RESULT" | jq -r '.data.identifier')
          STATUS=$(echo "$RESULT" | jq -r '.data.status')
          DURATION=$(echo "$RESULT" | jq -r '.data.timestamps.duration // "?"')
          SERVERS=$(echo "$RESULT" | jq -r '.data.servers | length')
          echo "deployment_id=$DEP_ID" >> "$GITHUB_OUTPUT"
          echo "status=$STATUS" >> "$GITHUB_OUTPUT"
          echo "duration=$DURATION" >> "$GITHUB_OUTPUT"
          echo "servers=$SERVERS" >> "$GITHUB_OUTPUT"

      - name: Comment on PR
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const status = '${{ steps.deploy.outputs.status }}' || 'unknown';
            const depId = '${{ steps.deploy.outputs.deployment_id }}';
            const duration = '${{ steps.deploy.outputs.duration }}';
            const servers = '${{ steps.deploy.outputs.servers }}';
            const icon = status === 'completed' ? ':white_check_mark:' : ':x:';

            const body = `${icon} **Deployment ${status}**

            | Field | Value |
            |-------|-------|
            | ID | \`${depId}\` |
            | Duration | ${duration}s |
            | Servers | ${servers} |
            | Revision | \`${{ github.event.pull_request.merge_commit_sha }}\` |`;

            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body
            });
```

## GitLab CI

```yaml
# .gitlab-ci.yml
deploy:
  stage: deploy
  image: ubuntu:latest
  variables:
    DEPLOYHQ_ACCOUNT: $DEPLOYHQ_ACCOUNT
    DEPLOYHQ_EMAIL: $DEPLOYHQ_EMAIL
    DEPLOYHQ_API_KEY: $DEPLOYHQ_API_KEY
    DEPLOYHQ_PROJECT: my-app
  script:
    - curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
    - dhq deploy --server production --revision $CI_COMMIT_SHA --wait --json
  only:
    - main
```

## Bitbucket Pipelines

```yaml
# bitbucket-pipelines.yml
pipelines:
  branches:
    main:
      - step:
          name: Deploy
          script:
            - curl -fsSL https://raw.githubusercontent.com/deployhq/deployhq-cli/main/install.sh | sh
            - dhq deploy --server production --revision $BITBUCKET_COMMIT --wait --json
```

Set `DEPLOYHQ_ACCOUNT`, `DEPLOYHQ_EMAIL`, and `DEPLOYHQ_API_KEY` as repository variables in Bitbucket.

## Tips for CI/CD

### Parsing JSON Output

Use `jq` to extract specific fields from JSON output:

```bash
# Get deployment status
dhq deployments show abc123 -p my-app --json | jq -r '.data.status'

# Get the latest deployment ID
dhq deployments list -p my-app --json | jq -r '.data.records[0].identifier'
```

### Non-Zero Exit Codes

The CLI returns non-zero exit codes on failure, so your CI pipeline will automatically fail if a deployment fails when using `--wait`.

### DEPLOYHQ_PROJECT Environment Variable

Set `DEPLOYHQ_PROJECT` to avoid passing `-p` on every command:

```bash
export DEPLOYHQ_PROJECT=my-app
dhq deploy --server production --wait
```

### Example Workflow Files

The CLI repository includes ready-to-use workflow files in the [`examples/github-actions/`](https://github.com/deployhq/deployhq-cli/tree/main/examples/github-actions) directory:

- **deploy.yml** -- Deploy on push to main with polling and failure logs
- **deploy-multi-env.yml** -- Staging on push, production on release, with auto-rollback
- **deploy-on-pr-merge.yml** -- Deploy on PR merge with a status comment on the PR

Copy these into your `.github/workflows/` directory and update the secrets to get started quickly.

### Security

- Always store credentials as CI secrets, never in pipeline configuration files
- Use the minimum required permissions for the API key
- Consider using a dedicated service account for CI/CD deployments
