DEV Community

Alex Spinov
Alex Spinov

Posted on

Gitea Has a Free API: Self-Hosted Git Service That Just Works

Gitea is a painless self-hosted Git service. It is written in Go, runs on minimal resources, and provides a GitHub-like experience with issues, pull requests, CI/CD, and a comprehensive REST API.

What Is Gitea?

Gitea is a community-managed lightweight code hosting solution. A single binary that runs on a Raspberry Pi, yet powerful enough for organizations with thousands of repositories.

Key Features:

  • Single binary, cross-platform
  • GitHub/GitLab-like UI
  • Issues, PRs, code review
  • Gitea Actions (GitHub Actions compatible)
  • Container registry
  • Package registries (npm, PyPI, Maven, etc.)
  • OAuth2 provider
  • Comprehensive REST and GraphQL API

Installation

# Docker
docker run -d --name gitea -p 3000:3000 -p 222:22 \
  -v gitea-data:/data gitea/gitea:latest

# Or binary
wget https://dl.gitea.com/gitea/1.22/gitea-1.22-linux-amd64
chmod +x gitea-*
./gitea-1.22-linux-amd64 web
Enter fullscreen mode Exit fullscreen mode

Gitea REST API

import requests

GITEA = "http://localhost:3000/api/v1"
TOKEN = "your-access-token"
HEADERS = {"Authorization": f"token {TOKEN}", "Content-Type": "application/json"}

# Create a repository
repo = requests.post(f"{GITEA}/user/repos", headers=HEADERS, json={
    "name": "my-project",
    "description": "A cool project",
    "private": False,
    "auto_init": True,
    "default_branch": "main"
}).json()
print(f"Created: {repo['full_name']} - {repo['html_url']}")

# List repositories
repos = requests.get(f"{GITEA}/user/repos", headers=HEADERS).json()
for r in repos:
    print(f"{r['full_name']}: {r['stars_count']} stars, {r['forks_count']} forks")

# Create an issue
issue = requests.post(f"{GITEA}/repos/myuser/my-project/issues", headers=HEADERS, json={
    "title": "Add CI/CD pipeline",
    "body": "We need automated testing and deployment.",
    "labels": [1, 2]
}).json()
print(f"Issue #{issue['number']}: {issue['title']}")
Enter fullscreen mode Exit fullscreen mode

Pull Requests

# Create a pull request
pr = requests.post(f"{GITEA}/repos/myuser/my-project/pulls", headers=HEADERS, json={
    "title": "Add user authentication",
    "body": "Implements JWT-based auth with refresh tokens",
    "head": "feature/auth",
    "base": "main"
}).json()
print(f"PR #{pr['number']}: {pr['html_url']}")

# Review a PR
requests.post(f"{GITEA}/repos/myuser/my-project/pulls/{pr['number']}/reviews", headers=HEADERS, json={
    "body": "LGTM! Clean implementation.",
    "event": "APPROVED"
})

# Merge
requests.post(f"{GITEA}/repos/myuser/my-project/pulls/{pr['number']}/merge", headers=HEADERS, json={
    "Do": "squash",
    "merge_message_field": "Add user authentication (#1)"
})
Enter fullscreen mode Exit fullscreen mode

File Operations

import base64

# Create a file
content = base64.b64encode(b"print('Hello from Gitea!')").decode()
requests.post(f"{GITEA}/repos/myuser/my-project/contents/hello.py", headers=HEADERS, json={
    "message": "Add hello script",
    "content": content
})

# Read a file
file_info = requests.get(f"{GITEA}/repos/myuser/my-project/contents/hello.py", headers=HEADERS).json()
content = base64.b64decode(file_info["content"]).decode()
print(f"Content: {content}")
Enter fullscreen mode Exit fullscreen mode

Webhooks

# Create webhook for push events
requests.post(f"{GITEA}/repos/myuser/my-project/hooks", headers=HEADERS, json={
    "type": "gitea",
    "config": {
        "url": "https://webhook.example.com/gitea",
        "content_type": "json"
    },
    "events": ["push", "pull_request", "issues"],
    "active": True
})
Enter fullscreen mode Exit fullscreen mode

Resources


Need to scrape web data for your projects? Check out my web scraping tools on Apify — production-ready actors for Reddit, Google Maps, and more. Questions? Email me at spinov001@gmail.com

Top comments (0)