# Contributing via Fork (External Contributor Flow)

Complete workflow for external contributors: fork a repository, create a branch, make changes, create a cross-repo PR, and keep the fork in sync.

## 1. Fork the Repository

```bash
UPSTREAM_OWNER="{owner}"
REPO="{repo}"

FORK=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/forks" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{}')
FORK_OWNER=$(echo "$FORK" | jq -r '.owner.login')
echo "Forked to ${FORK_OWNER}/${REPO}"
```

To fork into an organization:

```bash
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/forks" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{"organization": "{org}"}'
```

## 2. Create Branch on Fork

```bash
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/branches" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "new_branch_name": "{new_branch}",
    "old_branch_name": "{base_branch}"
  }'
```

## 3. Make Changes

Create or update files on the fork's branch:

```bash
# Create a new file
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/contents/docs/contributing.md" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "'$(echo -n "# Contributing\n\nThank you for contributing!" | base64)'",
    "message": "docs: add contributing guide",
    "branch": "{branch}"
  }'

# Update an existing file
FILE_INFO=$(curl -s "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/contents/README.md?ref={branch}" \
  -H "Authorization: token ${FORGEJO_PAT}")
FILE_SHA=$(echo "$FILE_INFO" | jq -r '.sha')
CURRENT_CONTENT=$(echo "$FILE_INFO" | jq -r '.content' | base64 -d)

# Modify and upload
NEW_CONTENT=$(echo "$CURRENT_CONTENT" | sed 's/teh/the/g')
curl -s -X PUT "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/contents/README.md" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "'$(echo -n "$NEW_CONTENT" | base64)'",
    "message": "docs: fix typos in README",
    "branch": "{branch}",
    "sha": "'"${FILE_SHA}"'"
  }'
```

## 4. Create Cross-Repo Pull Request

The PR is created on the **upstream** repository with the head referencing the fork:

```bash
PR=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/pulls" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "docs: fix typos in README and add contributing guide",
    "body": "## Summary\n\n- Fixed typos in README\n- Added contributing guide\n\nCloses #42",
    "head": "'"${FORK_OWNER}"':fix/typo-in-docs",
    "base": "{base_branch}"
  }')
PR_INDEX=$(echo "$PR" | jq -r '.number')
echo "Created PR #${PR_INDEX} on ${UPSTREAM_OWNER}/${REPO}"
```

**Important**: The `head` field uses the format `fork_owner:branch_name` for cross-repo PRs.

## 5. Sync Fork with Upstream

Keep your fork's default branch up to date with the upstream:

```bash
# Check if fork is behind upstream
UPSTREAM_HEAD=$(curl -s "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/branches/{branch}" \
  -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.commit.id')
FORK_HEAD=$(curl -s "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/branches/{branch}" \
  -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.commit.id')

echo "Upstream HEAD: ${UPSTREAM_HEAD}"
echo "Fork HEAD:     ${FORK_HEAD}"

if [ "$UPSTREAM_HEAD" != "$FORK_HEAD" ]; then
  echo "Fork is behind upstream. Syncing..."

  # Create a temporary PR from upstream to fork to sync
  SYNC_PR=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/pulls" \
    -H "Authorization: token ${FORGEJO_PAT}" \
    -H "Content-Type: application/json" \
    -d '{
      "title": "sync: update from upstream",
      "body": "Automated sync from upstream repository",
      "head": "{fork_owner}:{branch}",
      "base": "{base_branch}"
    }')
  SYNC_INDEX=$(echo "$SYNC_PR" | jq -r '.number')

  # Merge the sync PR
  curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/pulls/${SYNC_INDEX}/merge" \
    -H "Authorization: token ${FORGEJO_PAT}" \
    -H "Content-Type: application/json" \
    -d '{
      "Do": "rebase",
      "delete_branch_after_merge": false
    }'
  echo "Fork synced."
else
  echo "Fork is up to date."
fi
```

## 6. Check Sync Status and Update Feature Branch

After syncing the fork's master, rebase your feature branch:

```bash
# Check if feature branch is behind fork's master
FORK_MASTER=$(curl -s "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/branches/{branch}" \
  -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.commit.id')
FEATURE_HEAD=$(curl -s "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/branches/{branch}" \
  -H "Authorization: token ${FORGEJO_PAT}" | jq -r '.commit.id')

echo "Fork master: ${FORK_MASTER}"
echo "Feature branch: ${FEATURE_HEAD}"

# If the upstream PR exists, use the update endpoint
# This updates the PR branch to include latest base changes
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/pulls/${PR_INDEX}/update?style=rebase" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

## Complete Script

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

UPSTREAM_OWNER="{owner}"
REPO="{repo}"

echo "=== Fork & Contribute Workflow ==="

# 1. Fork
FORK=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/forks" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{}')
FORK_OWNER=$(echo "$FORK" | jq -r '.owner.login')
echo "Forked to ${FORK_OWNER}/${REPO}"

# 2. Create branch
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/branches" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{"new_branch_name": "{new_branch}", "old_branch_name": "{base_branch}"}' > /dev/null
echo "Created branch fix/my-change"

# 3. Make changes
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${FORK_OWNER}/${REPO}/contents/new-file.md" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "'$(echo -n "New content" | base64)'",
    "message": "Add new file",
    "branch": "{branch}"
  }' > /dev/null
echo "Made changes"

# 4. Create cross-repo PR
PR=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${UPSTREAM_OWNER}/${REPO}/pulls" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "fix: my contribution",
    "body": "Description of changes",
    "head": "'"${FORK_OWNER}"':fix/my-change",
    "base": "{base_branch}"
  }')
PR_INDEX=$(echo "$PR" | jq -r '.number')
echo "Created PR #${PR_INDEX}"

echo "=== Done ==="
echo "PR URL: ${FORGEJO_URL}/${UPSTREAM_OWNER}/${REPO}/pulls/${PR_INDEX}"
```
