# Commit Statuses

Commit statuses allow external services (CI systems, linters, security scanners) to mark commits with a state. They are the primary mechanism for checking whether CI has passed on a branch or pull request.

## Endpoints

### Get Combined Status

```
GET /repos/{owner}/{repo}/commits/{ref}/status
```

Returns a single combined status that aggregates all individual statuses for the given ref. The `ref` can be a branch name, tag name, or commit SHA.

The combined `state` follows these rules:
- `success` if all statuses are `success` (or no statuses exist)
- `pending` if any status is `pending`
- `failure` if any status is `failure`
- `error` if any status is `error`
- `warning` if any status is `warning` (and no failure/error)

### List Individual Statuses

```
GET /repos/{owner}/{repo}/commits/{ref}/statuses
```

Query parameters:
- `sort` (string) - Sort by: `oldest`, `recentupdate`, `leastupdate`, `leastindex`, `highestindex`
- `state` (string) - Filter by state: `pending`, `success`, `error`, `failure`, `warning`
- `page` (int) - Page number (1-based)
- `limit` (int) - Page size

### Create Commit Status

```
POST /repos/{owner}/{repo}/statuses/{sha}
```

Note: This endpoint uses `/statuses/{sha}` (not `/commits/{ref}/statuses`).

## Combined Status Response

```json
{
  "state": "success",
  "statuses": [
    {
      "id": 1,
      "context": "CI / build",
      "status": "success",
      "description": "Build passed",
      "target_url": "https://ci.example.com/builds/123",
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:35:00Z",
      "creator": { "login": "{username}" }
    },
    {
      "id": 2,
      "context": "CI / test",
      "status": "success",
      "description": "All tests passed",
      "target_url": "https://ci.example.com/builds/124",
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:36:00Z",
      "creator": { "login": "{username}" }
    }
  ],
  "total_count": 2,
  "sha": "abc123def456",
  "commit_url": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/git/commits/{sha}",
  "repository": { "id": 1, "full_name": "owner/repo" },
  "url": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/commits/{sha}/status"
}
```

### Alternative Status Endpoints (by SHA directly)

In addition to the `/commits/{ref}/...` endpoints above, there are equivalent endpoints under `/statuses/{sha}`:

```
GET /repos/{owner}/{repo}/statuses/{sha}
```

Lists commit statuses by SHA directly (same as `GET /commits/{sha}/statuses` but uses a different URL path). Parameters are the same: `sort`, `state`, `page`, `limit`.

```
POST /repos/{owner}/{repo}/statuses/{sha}
```

Creates a commit status (same as using the `/commits/` path). Body is `CreateStatusOption`.

```bash
# List statuses via /statuses/{sha}
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/${SHA}?limit=10" \
  -H "Authorization: token ${FORGEJO_PAT}"

# Create status via /statuses/{sha}
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/${SHA}" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{"state": "success", "context": "my-check", "description": "Check passed"}'
```

> **Note:** Both URL patterns (`/commits/{ref}/statuses` and `/statuses/{sha}`) work identically. The `/commits/{ref}` version additionally accepts branch names and tag names as `{ref}`, while `/statuses/{sha}` requires the full commit SHA.

---

## Individual Status Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | int | Unique status identifier |
| `context` | string | Status name (e.g., "CI / build", "security/scan") |
| `status` / `state` | string | `pending`, `success`, `error`, `failure`, `warning` |
| `description` | string | Human-readable description |
| `target_url` | string | URL linking to the CI job or details page |
| `created_at` | string | ISO 8601 timestamp |
| `updated_at` | string | ISO 8601 timestamp |
| `creator` | object | User who created the status |

## CreateStatusOption (POST Body)

```json
{
  "state": "success",
  "context": "CI / build",
  "description": "Build completed successfully",
  "target_url": "https://ci.example.com/builds/123"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `state` | string | **Yes** | `pending`, `success`, `error`, `failure`, `warning` |
| `context` | string | No | Name for the status check (e.g., "CI / build"). Defaults to "default" |
| `description` | string | No | Short description of the status |
| `target_url` | string | No | URL to link to (usually the CI job page) |

If you POST a status with the same `context` as an existing status, it **updates** that context rather than creating a duplicate.

## Use Cases

### Check CI Quality Gates

Get the combined status for a PR's head SHA to determine if CI has passed:

```bash
# Get the PR to find the head SHA
HEAD_SHA=$(curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/pulls/{index}" | jq -r '.head.sha')

# Check combined status
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/${HEAD_SHA}/status" | jq '.state'
```

### Create Custom Status Checks

Mark custom quality gates (linting, security scans, deploy previews, etc.):

```bash
# Post a custom status
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "success",
    "context": "security/trivy-scan",
    "description": "No vulnerabilities found",
    "target_url": "https://security.example.com/scan/456"
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/{sha}"
```

### Integration with Branch Protection

Branch protection rules can require specific status checks to pass before merging. The `status_check_contexts` field in branch protection references the `context` names from commit statuses.

## Curl Examples

### 1. Get Combined Status for a Branch

```bash
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/{branch}/status" | jq '{state, total_count}'
```

### 2. Get Combined Status for a PR's Head Commit

```bash
# First get the PR
HEAD_SHA=$(curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/pulls/{index}" | jq -r '.head.sha')

# Then get the status
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/${HEAD_SHA}/status"
```

### 3. List All Individual Statuses

```bash
# List all statuses for a commit
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/{sha}/statuses"

# Filter by state
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/{sha}/statuses?state=failure"

# With pagination
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/{sha}/statuses?page=1&limit=20"
```

### 4. Create a Pending Status

```bash
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "pending",
    "context": "CI / build",
    "description": "Build is running...",
    "target_url": "https://ci.example.com/builds/789"
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/{sha}"
```

### 5. Update to Success or Failure

```bash
# Mark as success (same context updates the existing status)
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "success",
    "context": "CI / build",
    "description": "Build passed in 2m 34s",
    "target_url": "https://ci.example.com/builds/789"
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/{sha}"

# Or mark as failure
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "state": "failure",
    "context": "CI / build",
    "description": "Build failed: test suite errors",
    "target_url": "https://ci.example.com/builds/789"
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/statuses/{sha}"
```

### 6. Using Status Checks with Branch Protection

```bash
# First, create status checks on commits (as shown above)
# Then reference those context names in branch protection settings.
#
# When creating/updating branch protection, include:
# "status_check_contexts": ["CI / build", "CI / test", "security/trivy-scan"]
#
# This ensures PRs cannot be merged until all listed contexts report success.
#
# Check current branch protection:
curl -s -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/branch_protections" | \
  jq '.[].status_check_contexts'
```
