# Forgejo Issue Dependencies API

Base URL: `https://git.cleverthis.com/api/v1`

All endpoints require authentication via `Authorization: token ${FORGEJO_PAT}` header.

Issue dependencies allow you to express relationships between issues:
- **Dependencies**: Issues that must be resolved before this issue can be completed ("this issue depends on X").
- **Blocks**: Issues that are blocked by this issue ("this issue blocks Y").

Dependencies can span across repositories within the same Forgejo instance.

**Note:** The repository must have dependency tracking enabled. This is typically on by default but can be toggled in repository settings.

---

## Dependency Object

When listing dependencies or blocks, the API returns full Issue objects (the same format as `GET /repos/{owner}/{repo}/issues/{index}`).

---

## Dependencies (Issues This One Depends On)

### List Dependencies

```
GET /repos/{owner}/{repo}/issues/{index}/dependencies
```

Returns all issues that the specified issue depends on (i.e., issues that must be completed before this one).

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number |
| `page` | integer | query | Page number (1-based). Default: `1` |
| `limit` | integer | query | Page size |

#### Response

Returns `200` with an array of Issue objects representing the dependencies.

#### Examples

```bash
# List all dependencies for issue #42
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"

# List dependencies with summary info
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies" \
  | jq '[.[] | {number, title, state, repository: .repository.full_name}]'

# Check if all dependencies are resolved
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies" \
  | jq '{
      total: length,
      open: [.[] | select(.state == "open")] | length,
      closed: [.[] | select(.state == "closed")] | length,
      all_resolved: (all(.[]; .state == "closed"))
    }'
```

---

### Add a Dependency

```
POST /repos/{owner}/{repo}/issues/{index}/dependencies
```

Creates a dependency relationship: the specified issue will depend on another issue.

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number |

#### Request Body — `IssueMeta`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `owner` | string | **Yes** | Owner of the repository containing the dependency issue |
| `repo` | string | **Yes** | Repository name containing the dependency issue |
| `index` | integer | **Yes** | Index of the issue to depend on |

#### Response

Returns `201` with the created dependency (Issue object).

#### Examples

```bash
# Make issue #42 depend on issue #10 (same repo)
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "{repo}",
    "index": 10
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"

# Make issue #42 depend on issue #5 in a different repo (cross-repo dependency)
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "core-lib",
    "index": 5
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"

# Add multiple dependencies in sequence
for DEP_INDEX in {index1} {index2} {index3}; do
  curl -s -X POST \
    -H "Authorization: token ${FORGEJO_PAT}" \
    -H "Content-Type: application/json" \
    -d "{
      \"owner\": \"{owner}\",
      \"repo\": \"{repo}\",
      \"index\": ${DEP_INDEX}
    }" \
    "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"
  echo ""
done
```

---

### Remove a Dependency

```
DELETE /repos/{owner}/{repo}/issues/{index}/dependencies
```

Removes a dependency relationship.

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number |

#### Request Body — `IssueMeta`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `owner` | string | **Yes** | Owner of the dependency issue's repository |
| `repo` | string | **Yes** | Repository name of the dependency issue |
| `index` | integer | **Yes** | Index of the dependency issue to remove |

#### Response

Returns `200` with the updated Issue object.

#### Examples

```bash
# Remove dependency on issue #10 from issue #42
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "{repo}",
    "index": 10
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"

# Remove cross-repo dependency
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "core-lib",
    "index": 5
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/dependencies"
```

---

## Blocks (Issues Blocked by This One)

### List Issues Blocked by This Issue

```
GET /repos/{owner}/{repo}/issues/{index}/blocks
```

Returns all issues that are blocked by the specified issue (i.e., issues that depend on this one being completed first).

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number |
| `page` | integer | query | Page number (1-based). Default: `1` |
| `limit` | integer | query | Page size |

#### Response

Returns `200` with an array of Issue objects that are blocked by this issue.

#### Examples

```bash
# List issues blocked by issue #42
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks"

# List blocked issues with summary
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks" \
  | jq '[.[] | {number, title, state, repository: .repository.full_name}]'

# Count how many issues this one is blocking
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks" \
  | jq 'length'
```

---

### Add a Blocking Relationship

```
POST /repos/{owner}/{repo}/issues/{index}/blocks
```

Declares that the specified issue blocks another issue.

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number (the blocker) |

#### Request Body — `IssueMeta`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `owner` | string | **Yes** | Owner of the blocked issue's repository |
| `repo` | string | **Yes** | Repository name of the blocked issue |
| `index` | integer | **Yes** | Index of the issue being blocked |

#### Response

Returns `201` with the blocked Issue object.

#### Examples

```bash
# Declare issue #42 blocks issue #50 (same repo)
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "{repo}",
    "index": 50
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks"

# Declare issue #42 blocks issue #8 in another repo
curl -s -X POST \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "frontend",
    "index": 8
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks"
```

---

### Remove a Blocking Relationship

```
DELETE /repos/{owner}/{repo}/issues/{index}/blocks
```

Removes a blocking relationship.

#### Parameters

| Parameter | Type | In | Description |
|-----------|------|------|-------------|
| `owner` | string | path | **Required.** Repository owner |
| `repo` | string | path | **Required.** Repository name |
| `index` | integer | path | **Required.** Issue index number (the blocker) |

#### Request Body — `IssueMeta`

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `owner` | string | **Yes** | Owner of the blocked issue's repository |
| `repo` | string | **Yes** | Repository name of the blocked issue |
| `index` | integer | **Yes** | Index of the issue to unblock |

#### Response

Returns `200` with the updated Issue object.

#### Examples

```bash
# Remove blocking relationship: issue #42 no longer blocks issue #50
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "{repo}",
    "index": 50
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks"

# Remove cross-repo blocking
curl -s -X DELETE \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "owner": "{owner}",
    "repo": "frontend",
    "index": 8
  }' \
  "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/issues/{index}/blocks"
```

---

## Understanding the Relationship

The dependency/blocking system is two sides of the same relationship:

```
Issue A ---depends on---> Issue B
          (equivalently)
Issue B ---blocks-------> Issue A
```

- If you call `POST /repos/{owner}/{repo}/issues/A/dependencies` with `{index: B}`, then issue A depends on issue B.
- If you call `POST /repos/{owner}/{repo}/issues/B/blocks` with `{index: A}`, the same relationship is created from the other direction.

Both endpoints create the same underlying relationship. Use whichever makes more semantic sense for your workflow.

---

## Common Patterns

### Build a dependency tree for an issue

```bash
OWNER="{owner}"
REPO="{repo}"
INDEX="{index}"

echo "=== Issue #${INDEX} ==="
echo ""
echo "Depends on (must be done first):"
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/issues/${INDEX}/dependencies" \
  | jq -r '.[] | "  [" + .state + "] #" + (.number|tostring) + " - " + .title'

echo ""
echo "Blocks (waiting on this issue):"
curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/issues/${INDEX}/blocks" \
  | jq -r '.[] | "  [" + .state + "] #" + (.number|tostring) + " - " + .title'
```

### Check if an issue is ready to work on (all dependencies resolved)

```bash
OWNER="{owner}"
REPO="{repo}"
INDEX="{index}"

OPEN_DEPS=$(curl -s \
  -H "Authorization: token ${FORGEJO_PAT}" \
  "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/issues/${INDEX}/dependencies" \
  | jq '[.[] | select(.state == "open")] | length')

if [ "$OPEN_DEPS" -eq 0 ]; then
  echo "Issue #${INDEX} is ready to work on (no open dependencies)"
else
  echo "Issue #${INDEX} has ${OPEN_DEPS} unresolved dependency(ies)"
  curl -s \
    -H "Authorization: token ${FORGEJO_PAT}" \
    "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/issues/${INDEX}/dependencies" \
    | jq -r '.[] | select(.state == "open") | "  - #" + (.number|tostring) + " " + .title'
fi
```
