# Accessing CI/CD Logs via Web Interface

## The Challenge

Forgejo Actions logs are **not** exposed through the REST API in a structured way. While you can get workflow run metadata (status, conclusion, timestamps) via the REST API, the detailed step-by-step logs require web session authentication and HTML parsing.

## Step-by-Step Procedure

### 1. Find the Workflow Run

Use the REST API to list action runs and get run IDs:

```bash
# List recent workflow runs
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/actions/runs?limit=10" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

### 2. Get Commit Statuses for a PR

To find failing jobs associated with a pull request:

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

# Get statuses which include links to action jobs
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/commits/${HEAD_SHA}/statuses" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

The `target_url` field in each status object contains a relative URL like:

```
/{owner}/{repo}/actions/runs/{run_id}/jobs/6
```

This gives you the `run_id` (12345) and job index (6).

### 3. Web Login for Log Access

Since logs are only available through the web interface, you need to authenticate via a browser session:

```bash
COOKIE_JAR="/tmp/forgejo-cookies-$$.txt"

# Step 1: Get the login page and extract the CSRF token
LOGIN_PAGE=$(curl -sS -c "$COOKIE_JAR" "${FORGEJO_URL}/user/login")
CSRF=$(echo "$LOGIN_PAGE" | grep -oP 'name="_csrf"\s+content="\K[^"]+')

# Step 2: Perform login
curl -sS -L -c "$COOKIE_JAR" -b "$COOKIE_JAR" \
  --data-urlencode "_csrf=${CSRF}" \
  --data-urlencode "user_name=${FORGEJO_USERNAME}" \
  --data-urlencode "password=${FORGEJO_PASSWORD}" \
  "${FORGEJO_URL}/user/login" -o /dev/null

# Step 3: Access the action run page
ACTION_PAGE=$(curl -sS -b "$COOKIE_JAR" \
  "${FORGEJO_URL}/{owner}/{repo}/actions/runs/{run_id}/jobs/6")

# Step 4: Clean up
rm -f "$COOKIE_JAR"
```

### 4. Parse the HTML

The action run page contains log content embedded in the HTML. Extract it for analysis:

```bash
# Example: extract log lines from the HTML
echo "$ACTION_PAGE" | grep -oP 'log-msg[^>]*>\K[^<]+'
```

## Complete Script

Here is a complete script that finds failing CI for a PR and retrieves logs:

```bash
#!/bin/bash
set -euo pipefail

OWNER="{owner}"
REPO="{repo}"
PR_INDEX="{index}"
COOKIE_JAR="/tmp/forgejo-cookies-$$.txt"

# 1. Get PR head SHA
HEAD_SHA=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_INDEX}" \
  -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.head.sha')

echo "PR #${PR_INDEX} HEAD SHA: ${HEAD_SHA}"

# 2. Get commit statuses
STATUSES=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/commits/${HEAD_SHA}/statuses" \
  -H "Authorization: token ${FORGEJO_PAT}")

# 3. Find failing statuses
FAILING=$(echo "$STATUSES" | jq -r '.[] | select(.status == "failure" or .status == "error") | .target_url')

if [ -z "$FAILING" ]; then
  echo "No failing jobs found."
  exit 0
fi

echo "Failing jobs found:"
echo "$FAILING"

# 4. Web login
LOGIN_PAGE=$(curl -sS -c "$COOKIE_JAR" "${FORGEJO_URL}/user/login")
CSRF=$(echo "$LOGIN_PAGE" | grep -oP 'name="_csrf"\s+content="\K[^"]+')

curl -sS -L -c "$COOKIE_JAR" -b "$COOKIE_JAR" \
  --data-urlencode "_csrf=${CSRF}" \
  --data-urlencode "user_name=${FORGEJO_USERNAME}" \
  --data-urlencode "password=${FORGEJO_PASSWORD}" \
  "${FORGEJO_URL}/user/login" -o /dev/null

# 5. Fetch each failing job page
for job_url in $FAILING; do
  echo "=== Fetching logs for: ${job_url} ==="
  PAGE=$(curl -sS -b "$COOKIE_JAR" "${FORGEJO_URL}${job_url}")

  # Extract log content (parsing depends on Forgejo version / HTML structure)
  echo "$PAGE" | grep -oP 'log-msg[^>]*>\K[^<]+' || echo "(Could not parse logs from HTML)"
  echo ""
done

# 6. Clean up
rm -f "$COOKIE_JAR"
```

## Important Notes

- The CSRF token is in a `<meta name="_csrf" content="...">` tag on the login page
- After successful login, the session cookie `i_like_gitea` is set in the cookie jar
- Job URLs follow the pattern: `/{owner}/{repo}/actions/runs/{run_id}/jobs/{job_index}`
- Job indices are **0-based** (first job is index 0)
- Log content is embedded in the HTML page and the exact structure may vary between Forgejo versions
- The web login requires `FORGEJO_USERNAME` and `FORGEJO_PASSWORD` environment variables (separate from the PAT)
- Some Forgejo instances may have 2FA enabled, which complicates automated web login
- Consider caching the session cookie if you need to make multiple requests

## Alternative: Workflow Run Metadata via REST

While full logs require web access, you can get run-level metadata via REST:

```bash
# List workflow runs (metadata only - no step logs)
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/actions/runs" \
  -H "Authorization: token ${FORGEJO_PAT}"

# Get a specific run
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/actions/runs/{run_id}" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

This gives you status, conclusion, timing, and triggering information - but not the actual log output from each step.
