2
0
Code
logikonline 26793bf898 feat(ai): add ai operation logging and org settings models
Add database models and infrastructure for AI operation tracking and organization-level AI configuration.

OperationLog model tracks all AI operations for auditing, including:
- Operation type, tier, and trigger event
- Token usage (input/output)
- Status tracking (pending, success, failed, escalated)
- Performance metrics (duration)
- Rate limiting support via CountRecentOperations

OrgAISettings model stores per-organization AI configuration:
- Provider and model selection
- Encrypted API key storage
- Rate limits (max operations per hour)
- Allowed operations whitelist
- Agent mode permissions

Also adds AI unit type to repository units for enabling/disabling AI features per repo.
2026-02-11 23:46:57 -05:00
2026-01-10 08:22:37 -05:00
2025-10-29 19:34:40 +01:00
2025-12-18 14:05:49 -08:00
2025-11-20 21:53:44 +00:00
2023-01-24 18:52:38 +00:00
2026-01-17 09:02:21 -05:00
2026-01-17 09:02:21 -05:00
2016-11-08 08:42:05 +01:00
2026-01-23 00:54:56 +00:00
2025-09-06 09:56:18 -07:00
2025-10-23 08:35:48 +00:00

GitCaddy

The AI-native Git platform. Self-hosted, fast, and designed for the age of AI-assisted development.

Table of Contents

What is GitCaddy?

GitCaddy transforms Git hosting into an AI-ready platform. While traditional Git servers treat AI tools as an afterthought, GitCaddy is built from the ground up with structured APIs, capability discovery, and intelligent context that AI assistants need to write correct code, generate valid CI/CD workflows, and understand your projects deeply.

Key differentiators:

  • V2 API - Modern, AI-optimized endpoints with batch operations, streaming, and structured errors
  • Runner Capability Discovery - AI tools query runner capabilities before generating workflows
  • Action Compatibility Database - Curated compatibility matrix prevents workflow errors
  • AI Context APIs - Rich, structured repository and issue intelligence
  • Workflow Validation - Pre-flight checks for CI/CD workflows before commit
  • Comprehensive Platform - Full-featured Git hosting with collaboration, CI/CD, package registry, and enterprise features

Key Features

V2 API - Modern, AI-Optimized Interface

A complete API redesign focused on AI tool consumption:

Feature Description
Batch Operations Fetch up to 100 files in a single request
Streaming NDJSON streams for progressive processing
Idempotency Built-in support for safe request retries
Structured Errors Machine-readable error codes, not just HTTP status
Request Tracking Every request gets a unique ID for debugging
Health Checks Kubernetes-compatible liveness/readiness probes
Operation Progress Server-Sent Events for long-running operations
GET  /api/v2/batch/files          # Bulk file retrieval
POST /api/v2/stream/files         # NDJSON streaming
GET  /api/v2/operations/{id}      # Operation status
GET  /api/v2/health/ready         # Readiness probe

AI Context APIs - Repository Intelligence

Purpose-built endpoints that give AI tools the context they need:

Repository Summary (/api/v2/ai/repo/summary)

{
  "name": "my-project",
  "primary_language": "Go",
  "project_type": "application",
  "build_system": "go modules",
  "test_framework": "go test",
  "suggested_entry_points": ["cmd/main.go", "internal/app/"],
  "config_files": ["go.mod", "Makefile", ".gitea/workflows/"],
  "language_stats": {"Go": 45000, "YAML": 2000}
}

Repository Navigation (/api/v2/ai/repo/navigation)

  • Directory tree with depth control
  • Important paths ranked by priority (entry points, tests, docs)
  • File type distribution

Issue Context (/api/v2/ai/issue/context)

  • Issue details with all comments
  • Related issues and code references
  • AI hints: category (bug/feature), complexity estimation, suggested files

Runner Capability Discovery

Runners report their capabilities. AI tools query before generating workflows.

Endpoint: GET /api/v2/repos/{owner}/{repo}/actions/runners/capabilities

{
  "runners": [
    {
      "id": 1,
      "name": "ubuntu-runner",
      "status": "online",
      "labels": ["ubuntu-latest", "docker"],
      "capabilities": {
        "os": "linux",
        "arch": "amd64",
        "docker": true,
        "docker_compose": true,
        "shell": ["bash", "sh"],
        "tools": {
          "node": ["18.19.0", "20.10.0"],
          "go": ["1.21.5", "1.22.0"],
          "python": ["3.11.6", "3.12.0"]
        },
        "features": {
          "cache": true,
          "services": true
        }
      }
    }
  ],
  "platform": {
    "type": "gitea",
    "version": "1.26.0",
    "supported_actions": {
      "actions/checkout": {"versions": ["v3", "v4"]},
      "actions/setup-node": {"versions": ["v3", "v4"]},
      "actions/upload-artifact": {"versions": ["v3"], "notes": "v4 not supported"}
    },
    "unsupported_features": [
      "GitHub-hosted runners",
      "OIDC token authentication"
    ]
  },
  "workflow_hints": {
    "preferred_checkout": "actions/checkout@v4",
    "artifact_upload_alternative": "Use Gitea API for artifacts"
  }
}

Workflow Validation

Validate workflows before committing. Catch incompatibilities early.

Endpoint: POST /api/v2/repos/{owner}/{repo}/actions/workflows/validate

// Request
{
  "content": "name: Build\non: push\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/upload-artifact@v4"
}

// Response
{
  "valid": false,
  "warnings": [
    {
      "line": 8,
      "action": "actions/upload-artifact@v4",
      "severity": "error",
      "message": "actions/upload-artifact@v4 is not supported",
      "suggestion": "Use actions/upload-artifact@v3"
    }
  ],
  "runner_match": [
    {
      "job": "build",
      "runs_on": ["ubuntu-latest"],
      "matched_runners": ["ubuntu-runner-1"],
      "capabilities_met": true
    }
  ]
}

Action Compatibility Database

Built-in knowledge of GitHub Action compatibility:

Action Compatible Versions Notes
actions/checkout v2, v3, v4 Fully compatible
actions/setup-node v2, v3, v4 Fully compatible
actions/setup-go v3, v4, v5 Fully compatible
actions/setup-python v4, v5 Fully compatible
actions/cache v3, v4 Fully compatible
actions/upload-artifact v2, v3 v4 not supported
actions/download-artifact v2, v3 v4 not supported

Core Repository Management

  • Repository Operations: Create, fork, mirror (push/pull), and migrate repositories from external services
  • Branch & Tag Management: Branch protection rules with status checks, approval requirements, and reorderable protection rules
  • Code Browsing: Commit history, blame view, diff visualization, and file tree navigation with Vue-based sidebar
  • File Operations: Web-based editor for uploading, editing, and deleting files
  • Code Search: Full-text search across repository files
  • Release Management: Create releases with automatic release notes generation and archive old releases
  • Wiki Pages: Markdown-based documentation with full editing capabilities
  • Git LFS Support: Large File Storage for binary assets

Collaboration Tools

  • Issues: Labels, milestones, assignments, dependencies, and time tracking with real-time stopwatch
  • Pull Requests: Code review workflows with approval requirements and multiple merge strategies
  • Project Boards: Kanban-style boards with drag-and-drop organization using Sortable.js
  • Comments & Reactions: Mention autocomplete with Tribute.js, emoji reactions, and threaded discussions
  • Notifications: Comprehensive notification system for repository activity
  • Activity Tracking: Contribution graphs and activity heatmaps

CI/CD & Actions

  • Workflow Execution: Run GitHub Actions-compatible workflows with monitoring and logs
  • Runner Management: Track bandwidth, disk usage, and online/offline status
  • Job Queue: Monitor job status and view detailed execution logs
  • Secrets & Variables: Encrypted secrets management with CI/CD integration
  • Status Checks: Integrate workflow results into branch protection rules

Package Registry

Multi-format package hosting with versioning and dependency management:

  • Supported Formats: Alpine, Arch, Cargo, Chef, Composer, Conda, Debian, Docker, Go, Helm, Maven, npm, NuGet, PyPI, RPM, RubyGems, Swift, Vagrant
  • Access Controls: Global and per-package permission management
  • Version Management: Full version history and dependency tracking

Vault System (Pro/Enterprise)

Enterprise-grade encrypted secrets management:

  • Encrypted Storage: Version history for all secrets with rollback capabilities
  • Audit Logging: Comprehensive access logs with extended retention for Enterprise tier
  • CI/CD Integration: Generate tokens for workflow access to secrets
  • Tiered Licensing: Solo, Pro, Team, and Enterprise tiers with different feature sets

AI-Powered Features

  • AI Code Review: Automated code review suggestions on pull requests
  • Issue Triage: Automatic categorization and priority assignment
  • Code Explanation: Generate documentation and explain complex code
  • Error Diagnosis: AI learning patterns for debugging assistance

Landing Pages & Public Releases

Customizable repository landing pages with optional public access for private repositories:

  • Custom Domains: Configure custom domains with SSL management
  • Templates: Choose from pre-built templates or create custom designs
  • Branding: Logos, icons, and theme customization
  • Public Access: Expose landing pages and releases for private repos (perfect for commercial software with public downloads)

Configure in .gitea/landing.yaml:

enabled: true
public_landing: true  # Allow unauthenticated access to landing page

hero:
  title: "My App"
  tagline: "The best app ever"

advanced:
  public_releases: true  # Allow unauthenticated access to releases

API Endpoints (no auth required when enabled):

GET /api/v2/repos/{owner}/{repo}/pages/config    # Landing page config
GET /api/v2/repos/{owner}/{repo}/pages/content   # Landing page content
GET /api/v2/repos/{owner}/{repo}/releases        # List releases
GET /api/v2/repos/{owner}/{repo}/releases/latest # Latest release

App Update API (Electron/Squirrel Compatible)

Purpose-built endpoint for desktop app auto-updates with Squirrel-compatible JSON format.

Endpoint: GET /api/v2/repos/{owner}/{repo}/releases/update

Query Parameters:

Parameter Description Default
version Current app version (semver) Required
platform darwin, windows, linux Runtime OS
arch x64, arm64 Runtime arch
channel stable, beta, alpha stable

Response (200 OK - update available):

{
  "url": "https://git.example.com/owner/repo/releases/download/v1.2.0/App-darwin-arm64.zip",
  "name": "v1.2.0",
  "notes": "Release notes in markdown...",
  "pub_date": "2026-01-10T12:00:00Z",
  "platform": {
    "size": 45000000,
    "releases_url": "https://...",  // Windows RELEASES file
    "nupkg_url": "https://..."      // Windows nupkg
  }
}

Response (204 No Content): No update available

Electron Integration:

// In your Electron app
import { autoUpdater } from 'electron'

const version = app.getVersion()
const platform = process.platform
const arch = process.arch === 'arm64' ? 'arm64' : 'x64'

autoUpdater.setFeedURL({
  url: `https://git.example.com/api/v2/repos/owner/repo/releases/update?version=${version}&platform=${platform}&arch=${arch}`
})

autoUpdater.checkForUpdates()

Release Archive

Archive old releases without deleting them:

  • Toggle archived status via UI or API
  • Filter releases by archived state
  • Archived releases hidden by default with toggle to show
  • Preserves release history for compliance
POST   /api/v1/repos/{owner}/{repo}/releases/{id}/archive
DELETE /api/v1/repos/{owner}/{repo}/releases/{id}/archive
GET    /api/v1/repos/{owner}/{repo}/releases?archived=false

Security & Authentication

  • Two-Factor Authentication: TOTP-based 2FA with recovery codes
  • WebAuthn/Hardware Keys: Passkey support with credential management
  • SSH/GPG Keys: Key management with parsing and validation
  • OAuth2/OpenID Connect: Integration with external identity providers
  • LDAP/SAML/SSPI: Enterprise authentication support
  • Signed Commits: GPG signature verification
  • Branch Protection: Enforce status checks and approval requirements

Organization Management

  • Team Management: Granular permissions with role-based access control
  • Member Roles: Owner, member, and restricted user types
  • Visibility Controls: Public, private, and limited organization visibility
  • Pinned Repositories: Feature important projects on organization pages
  • License Management: Organization-level licensing for Pro/Enterprise features

Advanced UI Features

  • Real-time Updates: EventSource/SharedWorker for synchronized time tracking across tabs
  • Interactive Tables: Sortable columns and filterable data
  • Math Rendering: LaTeX equations with KaTeX
  • Diagram Rendering: Mermaid diagrams in isolated iframes
  • Code Block Enhancements: Copy-to-clipboard buttons and syntax highlighting
  • Task Lists: Interactive checkboxes in Markdown
  • Terminal Playback: Asciinema recording playback
  • Accessibility: ARIA attributes, keyboard navigation, and screen reader support
  • Responsive Design: Mobile-friendly interface with overflow menus
  • Toast Notifications: Non-intrusive status messages with Toastify.js
  • Tooltips: Context-sensitive help with Tippy.js
  • Image Gallery: Project showcase capabilities

Installation

From Binary

Download from Releases:

# Linux (amd64)
curl -L -o gitcaddy-server https://git.marketally.com/gitcaddy/gitcaddy-server/releases/latest/download/gitcaddy-server-linux-amd64
chmod +x gitcaddy-server
./gitcaddy-server web

# macOS (arm64)
curl -L -o gitcaddy-server https://git.marketally.com/gitcaddy/gitcaddy-server/releases/latest/download/gitcaddy-server-darwin-arm64
chmod +x gitcaddy-server
./gitcaddy-server web

# Windows (amd64)
# Download gitcaddy-server-windows-amd64.exe and run:
gitcaddy-server.exe web

The server will start on http://localhost:3000 by default. On first run, you'll be redirected to the installation wizard.

From Source

# Clone the repository
git clone https://git.marketally.com/gitcaddy/gitcaddy-server.git
cd gitcaddy-server

# Build with SQLite support
TAGS="bindata sqlite sqlite_unlock_notify" make build

# Run the server
./gitcaddy-server web

Requirements:

  • Go 1.24+ (see go.mod)
  • Node.js 22.6+ (for frontend)
  • Make

Docker

# Run with Docker
docker run -d \
  --name gitcaddy \
  -p 3000:3000 \
  -v ./data:/data \
  gitcaddy/gitea:latest

# Or use Docker Compose
version: "3"
services:
  gitcaddy:
    image: gitcaddy/gitea:latest
    ports:
      - "3000:3000"
    volumes:
      - ./data:/data
    restart: unless-stopped

Configuration

Database Setup

GitCaddy supports multiple database backends. Configure during installation or in app.ini:

Supported Databases:

  • SQLite (default, no additional setup required)
  • MySQL 5.7+ / MariaDB 10.2+
  • PostgreSQL 10+
  • MSSQL 2008+

Example MySQL Configuration:

[database]
DB_TYPE = mysql
HOST = 127.0.0.1:3306
NAME = gitcaddy
USER = gitcaddy
PASSWD = your_password

Example PostgreSQL Configuration:

[database]
DB_TYPE = postgres
HOST = 127.0.0.1:5432
NAME = gitcaddy
USER = gitcaddy
PASSWD = your_password
SSL_MODE = disable

AI Features Configuration

Enable and configure AI-powered features in app.ini:

[server]
ROOT_URL = https://your-instance.com/

[actions]
ENABLED = true

[api]
; Enable V2 API (enabled by default)
ENABLE_V2_API = true

; Max files in batch request
MAX_BATCH_SIZE = 100

; Enable AI context endpoints
ENABLE_AI_CONTEXT = true

Authentication Sources

Configure external authentication through the admin dashboard or app.ini:

OAuth2 Providers:

  • GitHub, GitLab, Gitea, Bitbucket
  • Google, Microsoft, Discord, Twitter
  • Generic OAuth2 providers

LDAP/Active Directory:

[auth.ldap]
ENABLED = true
HOST = ldap.example.com
PORT = 389
BIND_DN = cn=admin,dc=example,dc=com
BIND_PASSWORD = password
USER_BASE = ou=users,dc=example,dc=com
USER_FILTER = (uid=%s)

SAML 2.0: Configure through the admin dashboard with your identity provider's metadata.

Email/SMTP Setup

Configure email notifications in app.ini. Email is required for account registration, password resets, notification delivery, and blog guest comment verification (anonymous commenters receive a 6-digit code via email to verify their identity).

[mailer]
ENABLED = true
FROM = noreply@your-instance.com
PROTOCOL = smtp+starttls
SMTP_ADDR = smtp.gmail.com
SMTP_PORT = 587
USER = your-email@gmail.com
PASSWD = your-app-password

Supported protocols: smtp+starttls (recommended), smtps, smtp, sendmail

Common provider examples:

Provider SMTP_ADDR SMTP_PORT PROTOCOL
Gmail smtp.gmail.com 587 smtp+starttls
Office 365 smtp.office365.com 587 smtp+starttls
Amazon SES email-smtp.us-east-1.amazonaws.com 587 smtp+starttls
Mailgun smtp.mailgun.org 587 smtp+starttls
SendGrid smtp.sendgrid.net 587 smtp+starttls

Note: Gmail requires an App Password (not your regular password) when 2FA is enabled. Amazon SES requires SMTP credentials generated from the SES console.

Unsplash Integration

Enable Unsplash image search for repository social card backgrounds (Media Kit). This allows repository admins to search and select high-quality background images directly from Unsplash.

[unsplash]
; Enable Unsplash integration for Media Kit background images
ENABLED = true
; Unsplash API access key (get one at https://unsplash.com/developers)
ACCESS_KEY = your_unsplash_access_key

To obtain an access key:

  1. Create an account at unsplash.com/developers
  2. Create a new application
  3. Copy the Access Key (the Secret Key is not needed)

When enabled, repository admins can search Unsplash from Settings > Media Kit when using the "Background Image" social card style. Attribution is handled automatically per Unsplash API guidelines.

Monetize / Subscriptions

Gate repository code access (source view, clone, archive downloads) behind paid subscriptions. Issues and releases remain accessible. Supports monthly, yearly, and lifetime pricing tiers with Stripe and PayPal payment providers.

1. Enable the feature in app.ini:

[monetize]
ENABLED = true

2. Configure payment providers in Site Administration > Monetize:

  • Enter your Stripe secret key, publishable key, and webhook secret
  • Enter your PayPal client ID, client secret, and webhook ID
  • Enable each provider individually

3. Enable subscriptions per repository in Repository Settings > Subscriptions > General:

  • Toggle "Enable Subscriptions" for the repository

4. Create subscription products in Repository Settings > Subscriptions > Products:

  • Add monthly, yearly, or lifetime products with pricing
  • Optionally link Stripe Price IDs and PayPal Plan IDs for recurring billing

How it works:

  • Users without an active subscription see a subscribe page (HTTP 402) when accessing gated code
  • Repository owners, admins, collaborators with write access, and site admins bypass the paywall
  • Webhooks from Stripe and PayPal automatically update subscription status (renewals, cancellations, failures)
  • The subscribe page at /{owner}/{repo}/subscribe presents product cards with embedded Stripe Elements and PayPal buttons

Webhook endpoints (configure these in your Stripe/PayPal dashboards):

POST /-/monetize/webhooks/stripe
POST /-/monetize/webhooks/paypal

Usage

Repository Operations

Creating Repositories:

  1. Click the "+" icon in the top navigation
  2. Select "New Repository"
  3. Choose a template (optional) or start from scratch
  4. Configure repository settings (visibility, README, .gitignore, license)

Forking:

  1. Navigate to any repository
  2. Click "Fork" in the top-right corner
  3. Select the destination organization or user

Mirroring:

  1. Create a new repository
  2. Enable "This repository is a mirror"
  3. Configure pull/push mirror settings
  4. Set synchronization schedule

Migration:

  1. Click "+" → "New Migration"
  2. Select source platform (GitHub, GitLab, Gitea, Gogs)
  3. Provide repository URL and credentials
  4. Choose items to migrate (issues, PRs, releases, wiki)

Project Management

Issues:

  • Create issues with labels, milestones, and assignments
  • Add dependencies between issues
  • Track time with the built-in stopwatch (synchronized across browser tabs)
  • Use mentions (@username) with autocomplete
  • Add reactions and threaded comments

Pull Requests:

  • Create PRs from branches or forks
  • Request reviews from team members
  • View inline diff with syntax highlighting
  • Approve/request changes with review comments
  • Merge with strategies: merge commit, squash, or rebase

Project Boards:

  • Create Kanban boards with custom columns
  • Drag and drop issues/PRs between columns
  • Filter by labels, milestones, or assignees
  • Track progress with visual indicators

CI/CD Workflows

Creating Workflows:

Create .gitea/workflows/build.yml:

name: Build and Test
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install
      - run: npm test

Validating Before Commit:

# Use the validation API
curl -X POST https://your-instance.com/api/v2/repos/owner/repo/actions/workflows/validate \
  -H "Authorization: token YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": "..."}'

Monitoring Workflows:

  • View workflow runs in the "Actions" tab
  • Check runner status and capabilities
  • View job logs in real-time
  • Re-run failed jobs

Package Registry Usage

Publishing npm Packages:

# Configure registry
npm config set registry https://your-instance.com/api/packages/owner/npm/

# Authenticate
npm login --registry=https://your-instance.com/api/packages/owner/npm/

# Publish
npm publish

Publishing Docker Images:

# Login
docker login your-instance.com

# Tag and push
docker tag myimage:latest your-instance.com/owner/myimage:latest
docker push your-instance.com/owner/myimage:latest

Other Formats: Refer to the package registry documentation for Maven, PyPI, Cargo, Helm, and other formats.

Vault Usage (Pro/Enterprise)

Creating Secrets:

  1. Navigate to repository settings → Vault
  2. Click "New Secret"
  3. Enter key-value pairs
  4. Secrets are automatically encrypted and versioned

Using in Workflows:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy
        env:
          API_KEY: ${{ secrets.API_KEY }}
        run: ./deploy.sh

Viewing Audit Logs:

  • Access audit logs in the Vault section
  • Filter by user, action, and date range
  • Export logs for compliance (Enterprise tier)

Rolling Back Secrets:

  1. View secret history
  2. Select a previous version
  3. Click "Restore"

Landing Pages Configuration

Creating a Landing Page:

  1. Create .gitea/landing.yaml in your repository:
enabled: true
public_landing: true  # For private repos with public landing page

hero:
  title: "My Amazing Project"
  tagline: "The best solution for your needs"
  cta_text: "Download Now"
  cta_link: "/releases/latest"

features:
  - title: "Fast"
    description: "Lightning-fast performance"
    icon: "⚡"
  - title: "Secure"
    description: "Enterprise-grade security"
    icon: "🔒"

gallery:
  - image: "screenshot1.png"
    caption: "Main interface"
  - image: "screenshot2.png"
    caption: "Advanced features"

advanced:
  custom_domain: "myproject.com"
  ssl_enabled: true
  public_releases: true
  1. Commit and push the file
  2. Access your landing page at https://your-instance.com/owner/repo/pages

AI Features Usage

AI Code Review:

  1. Create a pull request
  2. Enable AI review in PR settings
  3. AI will analyze changes and provide suggestions
  4. Review and apply suggestions as needed

Issue Triage:

  • AI automatically categorizes new issues
  • Suggests labels based on content
  • Estimates complexity
  • Recommends relevant files for investigation

Code Explanation:

  1. Select code in the file viewer
  2. Click "Explain with AI"
  3. View generated documentation

Using AI Context APIs:

# Get repository summary
curl https://your-instance.com/api/v2/ai/repo/summary?owner=owner&repo=repo \
  -H "Authorization: token YOUR_TOKEN"

# Get issue context
curl https://your-instance.com/api/v2/ai/issue/context?owner=owner&repo=repo&issue=123 \
  -H "Authorization: token YOUR_TOKEN"

# Get repository navigation
curl https://your-instance.com/api/v2/ai/repo/navigation?owner=owner&repo=repo&depth=3 \
  -H "Authorization: token YOUR_TOKEN"

GitCaddy Runner

For full capability reporting and optimal workflow execution, use the GitCaddy act_runner:

# Download
curl -L -o act_runner https://git.marketally.com/gitcaddy/act_runner/releases/latest/download/act_runner-linux-amd64
chmod +x act_runner

# Register with your GitCaddy instance
./act_runner register \
  --instance https://your-instance.com \
  --token YOUR_REGISTRATION_TOKEN \
  --name my-runner \
  --labels ubuntu-latest,docker

# Run the runner daemon
./act_runner daemon

Automatic Capability Detection:

The runner automatically detects and reports:

  • Operating system and architecture
  • Docker/Podman availability and version
  • Docker Compose support
  • Installed tools and their versions:
    • Node.js
    • Go
    • Python
    • Java
    • .NET
    • Rust
    • Ruby
    • PHP
  • Available shells (bash, sh, pwsh, cmd)
  • Cache support
  • Service containers support

Viewing Runner Capabilities:

Access runner capabilities through the API or UI:

curl https://your-instance.com/api/v2/repos/owner/repo/actions/runners/capabilities \
  -H "Authorization: token YOUR_TOKEN"

API Documentation

GitCaddy provides comprehensive API documentation:

  • Interactive Explorer: Visit /api/v2/docs on your instance for the Scalar API explorer
  • OpenAPI Specification: Download from /api/v2/swagger.json
  • Legacy API: V1 API documentation available at /api/swagger

Authentication:

All API endpoints require authentication via token:

# Create a token in Settings → Applications → Generate New Token

# Use in requests
curl https://your-instance.com/api/v2/repos/owner/repo \
  -H "Authorization: token YOUR_TOKEN"

Common API Operations:

# List repositories
GET /api/v2/user/repos

# Get repository details
GET /api/v2/repos/{owner}/{repo}

# Create an issue
POST /api/v2/repos/{owner}/{repo}/issues

# List pull requests
GET /api/v2/repos/{owner}/{repo}/pulls

# Get runner capabilities
GET /api/v2/repos/{owner}/{repo}/actions/runners/capabilities

# Validate workflow
POST /api/v2/repos/{owner}/{repo}/actions/workflows/validate

# Batch file retrieval
GET /api/v2/batch/files?paths=file1.go,file2.go&owner=owner&repo=repo

# Stream files (NDJSON)
POST /api/v2/stream/files

Internationalization

GitCaddy supports 12+ languages with full UI translation:

Supported Languages:

  • German (de-DE)
  • English (en-US)
  • Irish (ga-IE)
  • Hindi (hi-IN)
  • Hungarian (hu-HU)
  • Indonesian (id-ID)
  • Icelandic (is-IS)
  • Italian (it-IT)
  • Dutch (nl-NL)
  • Polish (pl-PL)
  • Brazilian Portuguese (pt-BR)
  • Portuguese (pt-PT)

Changing Language:

  1. Click your avatar in the top-right
  2. Select "Settings"
  3. Choose "Language" from the dropdown
  4. Save changes

Contributing Translations:

Translations are stored in JSON files at options/locale/. To contribute:

  1. Copy an existing locale file
  2. Translate all strings
  3. Submit a pull request

Building from Source

Requirements:

  • Go 1.24+ (see go.mod for exact version)
  • Node.js 22.6+
  • Make
  • Git

Build Commands:

# Clone the repository
git clone https://git.marketally.com/gitcaddy/gitcaddy-server.git
cd gitcaddy-server

# Full build (backend + frontend)
TAGS="bindata sqlite sqlite_unlock_notify" make build

# Backend only
make backend

# Frontend only
make frontend

# Run tests
make test

# Run with live reload (development)
make watch

# Generate API documentation
make generate-swagger

Build Tags:

  • bindata - Embed static assets into binary
  • sqlite - Enable SQLite support
  • sqlite_unlock_notify - Enable SQLite unlock notifications
  • pam - Enable PAM authentication
  • gogit - Use pure Go git implementation

Development Setup:

# Install frontend dependencies
npm install

# Run frontend in development mode
npm run dev

# Run backend with hot reload
make watch-backend

# Run tests with coverage
make test-coverage

Contributing

We welcome contributions! Here's how to get started:

  1. Fork the repository on GitCaddy
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes with clear commit messages
  4. Run tests: make test
  5. Run linters: make lint
  6. Submit a pull request with a clear description

Code Style:

  • Go: Follow standard Go conventions (gofmt, golint)
  • TypeScript: Use ESLint configuration in the repository
  • Commit messages: Use conventional commits format

Testing:

  • Write unit tests for new features
  • Ensure all tests pass before submitting
  • Add integration tests for API changes

Documentation:

  • Update README.md for user-facing changes
  • Add API documentation for new endpoints
  • Include code comments for complex logic

License

MIT License - see LICENSE for details.

Acknowledgments

GitCaddy is a fork of Gitea, the open-source self-hosted Git service. We thank the Gitea team and all contributors for building the foundation that makes GitCaddy possible.


Related Projects:

Project Description
gitcaddy/act_runner Runner with automatic capability detection
gitcaddy/actions-proto-go Protocol buffer definitions for Actions

Support:

GitCaddy Users Guide

A comprehensive guide to using GitCaddy, a self-hosted Git repository management platform with AI capabilities, encrypted secrets management, and enterprise features.

Table of Contents


Introduction

GitCaddy is a powerful, self-hosted Git repository management platform that provides a complete solution for version control, issue tracking, CI/CD workflows, package registry, and team collaboration. Built as an enhanced fork of Gitea, GitCaddy adds enterprise features including:

  • AI-powered code review and issue triage
  • Vault encrypted secrets management with audit logging
  • Package registry supporting npm, Maven, Docker, PyPI, Go, Cargo, NuGet, and more
  • Custom landing pages with SSL/TLS support
  • Comprehensive internationalization with 18+ supported languages
  • GitCaddy Actions for CI/CD automation
  • Advanced collaboration tools including project boards, wikis, and time tracking

This guide will walk you through everything you need to know to effectively use GitCaddy, from initial setup to advanced workflows.


Getting Started

Prerequisites

Before installing GitCaddy, ensure you have the following:

  • Go runtime (version 1.18 or higher)
  • Node.js and npm (for building frontend assets)
  • Git (version 2.0 or higher)
  • Database: PostgreSQL, MySQL, SQLite, or MSSQL
  • Operating System: Linux, macOS, or Windows

Installation

Follow these steps to install GitCaddy on your server:

1. Clone the Repository

git clone https://github.com/your-org/gitcaddy.git
cd gitcaddy

2. Build the Backend

# Install Go dependencies
go mod download

# Build the GitCaddy binary
go build -o gitcaddy

3. Build the Frontend

# Install Node.js dependencies
npm install

# Build frontend assets
npm run build

4. Configure the Database

Create a configuration file custom/conf/app.ini with your database settings:

[database]
DB_TYPE = postgres
HOST = localhost:5432
NAME = gitcaddy
USER = gitcaddy_user
PASSWD = your_secure_password

Supported database types: postgres, mysql, sqlite3, mssql

5. Start GitCaddy

./gitcaddy web

By default, GitCaddy runs on port 3000. Access it at http://localhost:3000

First-Time Setup

When you first access GitCaddy, you'll be guided through a web-based installation wizard:

  1. Database Configuration: Verify or adjust database connection settings
  2. General Settings: Configure site title, domain, and SSH/HTTP ports
  3. Administrator Account: Create your admin user account
  4. Optional Settings: Configure email, server paths, and additional features
  5. Install: Click "Install GitCaddy" to complete setup

After installation, you'll be redirected to your dashboard where you can start creating repositories and inviting users.


Basic Repository Operations

Creating a Repository

To create a new repository:

  1. Click the "+" icon in the top navigation bar

  2. Select "New Repository"

  3. Fill in the repository details:

    • Owner: Select your user or an organization
    • Repository Name: Choose a unique name
    • Description: Optional description of your project
    • Visibility: Public or Private
    • Initialize Repository: Optionally add README, .gitignore, and license
    • Template: Search for and select a repository template
  4. Click "Create Repository"

Example: Creating a Node.js project repository

Owner: myusername
Repository Name: my-nodejs-app
Description: A sample Node.js application
Visibility: Private
✓ Initialize with README
.gitignore: Node
License: MIT License

Cloning and Pushing Code

After creating a repository, clone it to your local machine:

# Clone via HTTPS
git clone https://gitcaddy.example.com/username/my-nodejs-app.git

# Or clone via SSH
git clone git@gitcaddy.example.com:username/my-nodejs-app.git

Add files and push your first commit:

cd my-nodejs-app
echo "# My Node.js App" > README.md
git add README.md
git commit -m "Initial commit"
git push origin main

Managing Branches and Tags

Creating a Branch

# Create and switch to a new branch
git checkout -b feature/new-feature

# Push the branch to GitCaddy
git push origin feature/new-feature

In the GitCaddy web interface:

  1. Navigate to your repository
  2. Click the branch dropdown (usually shows "main")
  3. Type a new branch name and click "Create branch"

Branch Protection Rules

Protect important branches from direct pushes:

  1. Go to SettingsBranches
  2. Click "Add Rule"
  3. Configure protection settings:
    • Require pull request reviews
    • Require status checks to pass
    • Restrict who can push
    • Enable force push protection

Creating Tags

# Create an annotated tag
git tag -a v1.0.0 -m "Release version 1.0.0"

# Push tags to GitCaddy
git push origin --tags

File Operations

GitCaddy provides a web-based file editor for quick changes:

  1. Navigate to a file in your repository
  2. Click the pencil icon to edit
  3. Make your changes in the markdown-aware editor
  4. Add a commit message
  5. Choose to commit directly or create a new branch
  6. Click "Commit Changes"

Uploading Files:

  1. Navigate to the target directory
  2. Click "Upload file"
  3. Drag and drop files or click to browse
  4. Add a commit message and commit

Deleting Files:

  1. Navigate to the file
  2. Click the trash icon
  3. Confirm deletion with a commit message

Collaboration Workflows

Working with Issues

Issues are the foundation of project tracking in GitCaddy. They support rich features including labels, milestones, assignments, time tracking, and dependencies.

Creating an Issue

  1. Navigate to your repository

  2. Click the "Issues" tab

  3. Click "New Issue"

  4. Fill in the details:

    • Title: Brief description of the issue
    • Description: Detailed explanation using markdown
    • Labels: Categorize the issue (bug, enhancement, question, etc.)
    • Milestone: Associate with a project milestone
    • Assignees: Assign team members
    • Projects: Add to a project board
  5. Click "Create Issue"

Example Issue:

Title: Add user authentication to API

Description:
## Problem
The API currently lacks authentication, allowing unauthorized access.

## Proposed Solution
Implement JWT-based authentication with the following endpoints:
- POST /api/auth/login
- POST /api/auth/register
- POST /api/auth/refresh

## Acceptance Criteria
- [ ] JWT tokens are generated on successful login
- [ ] Protected endpoints validate tokens
- [ ] Refresh token mechanism is implemented
- [ ] Unit tests cover all auth flows

Labels: enhancement, security
Milestone: v2.0.0
Assignees: @developer1, @developer2

Time Tracking

Track time spent on issues:

  1. Open an issue
  2. In the sidebar, find "Time Tracking"
  3. Click "Add Time" and enter hours/minutes
  4. View total time spent and estimates

Issue Dependencies

Create dependencies between issues:

  1. Open an issue
  2. In the description or comments, reference another issue: Depends on #123
  3. GitCaddy automatically creates a dependency link
  4. The dependent issue cannot be closed until dependencies are resolved

Pull Request Workflow

Pull requests (PRs) enable code review and collaborative development.

Creating a Pull Request

  1. Push your feature branch to GitCaddy

  2. Navigate to the repository

  3. Click "New Pull Request"

  4. Select the base branch (e.g., main) and compare branch (e.g., feature/new-feature)

  5. Review the diff visualization

  6. Fill in PR details:

    • Title: Descriptive title
    • Description: Explain changes, link related issues
    • Reviewers: Request reviews from team members
    • Labels, Milestone, Assignees: Same as issues
  7. Click "Create Pull Request"

Example PR Description:

## Changes
This PR implements user authentication for the API as described in #45.

## Implementation Details
- Added JWT middleware for token validation
- Created auth controller with login/register/refresh endpoints
- Implemented password hashing with bcrypt
- Added comprehensive unit tests (95% coverage)

## Testing
- All existing tests pass
- New tests cover authentication flows
- Manual testing completed on staging environment

Closes #45

Reviewing Pull Requests

As a reviewer:

  1. Open the pull request

  2. Navigate to the "Files changed" tab

  3. Review the diff:

    • Click on a line number to add inline comments
    • Suggest specific code changes
    • Mark files as reviewed
  4. Submit your review:

    • Comment: General feedback without approval
    • Approve: Approve the changes
    • Request Changes: Block merging until issues are addressed

Merging Pull Requests

Once approved and status checks pass:

  1. Click the "Merge Pull Request" button

  2. Choose a merge strategy:

    • Create a merge commit: Preserves all commits with a merge commit
    • Squash and merge: Combines all commits into one
    • Rebase and merge: Replays commits on top of base branch
  3. Confirm the merge

  4. Optionally delete the feature branch

Code Reviews

GitCaddy supports comprehensive code review features:

  • Inline comments: Comment on specific lines of code
  • Suggestion blocks: Propose code changes that can be committed directly
  • Review threads: Discussions can be marked as resolved
  • Status checks: Automated checks must pass before merging
  • Required approvals: Enforce minimum number of approvals

Making a code suggestion:

```suggestion
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

### Project Boards

Organize work using Kanban-style project boards:

1. Navigate to your repository
2. Click the **"Projects"** tab
3. Click **"New Project"**
4. Choose a template or start blank
5. Create columns (e.g., "To Do", "In Progress", "Done")
6. Add issues and pull requests to columns
7. Drag and drop cards between columns

**Best Practice**: Use automation rules to move cards automatically based on issue/PR status.

---

## Wiki Documentation

Every repository includes a wiki for documentation.

### Creating Wiki Pages

1. Navigate to the **"Wiki"** tab in your repository
2. Click **"New Page"**
3. Enter a page title
4. Write content using the EasyMDE markdown editor with live preview
5. Click **"Save Page"**

### Wiki Features

- **Markdown support**: Full markdown syntax including tables, code blocks, and images
- **Mermaid diagrams**: Embed flowcharts, sequence diagrams, and more
- **Math formulas**: Use KaTeX for mathematical notation
- **Page hierarchy**: Organize pages with forward slashes (e.g., `Getting Started/Installation`)
- **History**: View page revisions and revert changes
- **Search**: Full-text search across all wiki pages

**Example Wiki Page:**

```markdown
# API Documentation

## Authentication

All API requests require a JWT token in the Authorization header:

```http
GET /api/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Endpoints

GET /api/users

Returns a list of users.

Response:

{
  "users": [
    {"id": 1, "username": "alice"},
    {"id": 2, "username": "bob"}
  ]
}

Rate Limiting

API requests are limited to 100 requests per hour per user.


---

## CI/CD with GitCaddy Actions

GitCaddy Actions provides integrated CI/CD automation similar to GitHub Actions.

### Creating Workflows

Workflows are defined in YAML files stored in `.gitea/workflows/` directory.

#### Example: Node.js Test Workflow

Create `.gitea/workflows/test.yml`:

```yaml
name: Node.js Tests

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [14, 16, 18]
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Upload coverage
        uses: actions/upload-artifact@v3
        with:
          name: coverage-report
          path: coverage/

Commit and push this file to trigger the workflow.

Managing Runners

Runners execute your workflow jobs. GitCaddy supports self-hosted runners.

Registering a Runner

  1. Navigate to SettingsActionsRunners
  2. Click "Add Runner"
  3. Follow the instructions to download and configure the runner on your machine:
# Download runner
wget https://gitcaddy.example.com/actions/runner/download

# Extract and configure
./config.sh --url https://gitcaddy.example.com --token YOUR_RUNNER_TOKEN

# Start the runner
./run.sh

Monitoring Runners

  • View runner status (online/offline) in the Runners page
  • Check runner tasks and job history
  • Run bandwidth tests to verify connectivity

Secrets and Variables

Store sensitive data like API keys and passwords securely.

Adding Secrets

  1. Navigate to SettingsSecrets and VariablesActions
  2. Click "New repository secret"
  3. Enter a name (e.g., API_KEY) and value
  4. Click "Add secret"

Using Secrets in Workflows

steps:
  - name: Deploy to production
    run: ./deploy.sh
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}

Security Note: Secrets are encrypted and never exposed in logs.


Vault: Encrypted Secrets Management

Vault is an enterprise feature providing advanced encrypted secrets management with version history and audit logging.

Creating Secrets

  1. Navigate to SettingsVault

  2. Click "New Secret"

  3. Enter secret details:

    • Key: Secret identifier (e.g., production-db-password)
    • Value: Secret content (automatically encrypted)
    • Description: Optional description
  4. Click "Create Secret"

Using Secrets in CI/CD

Vault secrets can be accessed in workflows using access tokens.

Generate an Access Token

  1. In Vault settings, click "Access Tokens"

  2. Click "Generate Token"

  3. Configure token permissions:

    • Scope: Select specific secrets or all secrets
    • Expiration: Set token lifetime
    • Permissions: Read-only or read-write
  4. Copy the generated token (shown only once)

Use Token in Workflow

steps:
  - name: Fetch database credentials
    run: |
      curl -H "Authorization: Bearer ${{ secrets.VAULT_TOKEN }}" \
           https://gitcaddy.example.com/api/vault/secrets/production-db-password

Audit Logs and Version History

Vault maintains comprehensive audit logs:

  1. Navigate to VaultAudit Logs

  2. View all operations:

    • Secret creation, updates, deletions
    • Access token generation and usage
    • User who performed each action
    • Timestamp of each operation
  3. Version History: Click on a secret to view all previous versions

  4. Rollback: Restore a previous version if needed

Vault Licensing Tiers:

  • Solo: Basic secrets management
  • Pro: Advanced access controls
  • Team: Multi-user collaboration features
  • Enterprise: Full audit logging and compliance features

Package Registry

GitCaddy includes a multi-format package registry supporting popular ecosystems.

Publishing Packages

npm Packages

Configure npm to use GitCaddy registry:

# Set registry URL
npm config set registry https://gitcaddy.example.com/api/packages/username/npm/

# Authenticate
npm login --registry=https://gitcaddy.example.com/api/packages/username/npm/

# Publish package
npm publish

Docker Images

# Login to registry
docker login gitcaddy.example.com

# Tag image
docker tag myimage:latest gitcaddy.example.com/username/myimage:latest

# Push image
docker push gitcaddy.example.com/username/myimage:latest

Maven Packages

Add to your pom.xml:

<distributionManagement>
  <repository>
    <id>gitcaddy</id>
    <url>https://gitcaddy.example.com/api/packages/username/maven</url>
  </repository>
</distributionManagement>

Deploy with Maven:

mvn deploy

Python Packages (PyPI)

Configure .pypirc:

[distutils]
index-servers = gitcaddy

[gitcaddy]
repository = https://gitcaddy.example.com/api/packages/username/pypi
username = your-username
password = your-token

Upload package:

python setup.py sdist bdist_wheel
twine upload --repository gitcaddy dist/*

Installing Packages

GitCaddy provides installation instructions for each package in the web interface:

  1. Navigate to Packages in your repository or user profile
  2. Click on a package
  3. View ecosystem-specific installation commands

Example for npm:

npm install --registry=https://gitcaddy.example.com/api/packages/username/npm/ package-name

AI-Powered Features

GitCaddy integrates AI capabilities to enhance code quality and productivity.

AI Code Review

Enable AI-assisted code reviews to receive automated feedback on pull requests.

Enabling AI Code Review

  1. Navigate to Repository SettingsAI Features
  2. Enable "AI Code Review"
  3. Configure review preferences:
    • Review depth: Quick scan or comprehensive analysis
    • Focus areas: Security, performance, best practices
    • Auto-comment: Automatically post suggestions as PR comments

How It Works

When a pull request is created:

  1. AI analyzes the code changes

  2. Identifies potential issues:

    • Security vulnerabilities
    • Performance bottlenecks
    • Code smells and anti-patterns
    • Style inconsistencies
  3. Posts suggestions as PR comments

  4. Provides explanations and recommended fixes

Example AI Comment:

🤖 AI Code Review

Potential Security Issue: SQL query is vulnerable to injection attacks.

Location: src/database.js:45

Recommendation: Use parameterized queries instead of string concatenation.

// Instead of:
const query = `SELECT * FROM users WHERE id = ${userId}`;

// Use:
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);

AI Issue Triage

AI automatically categorizes and prioritizes new issues.

Enabling AI Issue Triage

  1. Navigate to Repository SettingsAI Features
  2. Enable "AI Issue Triage"
  3. Configure triage rules:
    • Auto-label: Automatically apply labels based on content
    • Priority assignment: Suggest priority levels
    • Similar issues: Link to related issues

How It Works

When an issue is created:

  1. AI analyzes the issue title and description
  2. Suggests appropriate labels (bug, enhancement, documentation, etc.)
  3. Identifies priority based on keywords and context
  4. Finds similar existing issues to prevent duplicates

Code Explanation

Get AI-generated explanations for complex code.

Using Code Explanation

  1. Navigate to a file in your repository
  2. Select a code block
  3. Click the "Explain with AI" button
  4. View the explanation in plain language

Example:

const memoize = (fn) => {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
};

AI Explanation:

This code implements a memoization function, which is a performance optimization technique. It creates a cache to store the results of expensive function calls. When the function is called with the same arguments again, it returns the cached result instead of recalculating it. This is useful for pure functions with expensive computations.


Organizations and Teams

Organizations enable collaborative management of multiple repositories with team-based permissions.

Creating Organizations

  1. Click the "+" icon in the top navigation

  2. Select "New Organization"

  3. Fill in organization details:

    • Organization Name: Unique identifier
    • Display Name: Full name
    • Description: Organization purpose
    • Website: Optional URL
    • Location: Optional location
  4. Click "Create Organization"

Managing Teams

Teams group users within an organization and control access to repositories.

Creating a Team

  1. Navigate to your organization

  2. Click the "Teams" tab

  3. Click "New Team"

  4. Configure team settings:

    • Team Name: Descriptive name
    • Description: Team purpose
    • Visibility: Visible or hidden
  5. Click "Create Team"

Adding Team Members

  1. Open the team
  2. Click "Add Member"
  3. Search for users and click "Add"
  4. Assign roles:
    • Member: Standard access
    • Admin: Can manage team settings

Team Permissions

Control repository access per team:

  1. Navigate to Teams → Select a team
  2. Click "Repositories"
  3. Click "Add Repository"
  4. Select repository and set permissions:
    • Read: View code and issues
    • Write: Push commits, create issues/PRs
    • Admin: Full repository management

Best Practice: Use teams to implement the principle of least privilege. Grant only the permissions necessary for each team's responsibilities.


Landing Pages and Custom Domains

Create professional landing pages for your repositories with custom domains.

Enabling Landing Pages

  1. Navigate to Repository SettingsPages

  2. Enable "Landing Pages"

  3. Configure page settings:

    • Source: Select branch and directory (e.g., main/docs)
    • Custom Domain: Enter your domain (e.g., docs.myproject.com)
    • SSL/TLS: Enable HTTPS with automatic certificate
  4. Customize your landing page:

    • Hero Section: Add title, subtitle, and call-to-action
    • Features: Highlight key features with icons
    • Pricing: Display pricing tiers
    • Branding: Upload logo and customize colors
  5. Click "Save Settings"

Configuring Custom Domains

  1. In your DNS provider, add a CNAME record:

    docs.myproject.com CNAME gitcaddy.example.com
    
  2. In GitCaddy Pages settings, enter the custom domain

  3. Click "Verify Domain"

  4. Enable "Enforce HTTPS" for automatic SSL certificate

Your landing page will be accessible at https://docs.myproject.com

SEO Optimization

Optimize landing pages for search engines:

  1. Navigate to PagesSEO Settings
  2. Configure meta tags:
    • Title: Page title for search results
    • Description: Meta description
    • Keywords: Relevant keywords
    • Open Graph: Social media preview settings

Authentication and Security

GitCaddy provides multiple authentication methods and security features.

Two-Factor Authentication

Enhance account security with 2FA.

Enabling 2FA

  1. Navigate to SettingsSecurity
  2. Click "Enable Two-Factor Authentication"
  3. Scan the QR code with an authenticator app (Google Authenticator, Authy, etc.)
  4. Enter the verification code
  5. Save recovery codes in a secure location
  6. Click "Enable 2FA"

WebAuthn (Hardware Keys)

Use hardware security keys for passwordless authentication:

  1. Navigate to SettingsSecurityWebAuthn
  2. Click "Add Security Key"
  3. Enter a nickname for the key
  4. Follow browser prompts to register your key
  5. Test the key by logging out and back in

SSH and GPG Keys

Adding SSH Keys

  1. Generate an SSH key pair on your machine:

    ssh-keygen -t ed25519 -C "your_email@example.com"
    
  2. Navigate to SettingsSSH / GPG Keys

  3. Click "Add Key"

  4. Paste your public key (~/.ssh/id_ed25519.pub)

  5. Give it a descriptive name

  6. Click "Add Key"

Test your SSH connection:

ssh -T git@gitcaddy.example.com

Signing Commits with GPG

  1. Generate a GPG key:

    gpg --full-generate-key
    
  2. Export your public key:

    gpg --armor --export your_email@example.com
    
  3. Navigate to SettingsSSH / GPG KeysGPG Keys

  4. Click "Add Key" and paste your public key

  5. Configure Git to sign commits:

    git config --global user.signingkey YOUR_KEY_ID
    git config --global commit.gpgsign true
    

Signed commits display a "Verified" badge in GitCaddy.

OAuth2 and SSO

Configure external authentication providers for single sign-on.

Supported Providers

  • GitHub
  • GitLab
  • Google
  • Microsoft Azure AD
  • LDAP/Active Directory
  • SAML 2.0
  • OpenID Connect

Configuring OAuth2 (Admin)

  1. Navigate to Site AdministrationAuthentication Sources

  2. Click "Add Authentication Source"

  3. Select provider type (e.g., OAuth2)

  4. Configure provider settings:

    • Client ID: From provider
    • Client Secret: From provider
    • Authorization URL: Provider-specific
    • Token URL: Provider-specific
    • User Info URL: Provider-specific
  5. Click "Add Authentication Source"

Users can now log in using the external provider.


Customization and Settings

User Preferences

Personalize your GitCaddy experience:

  1. Navigate to SettingsProfile

  2. Configure preferences:

    • Display Name: Your full name
    • Email: Primary email address
    • Website: Personal or company website
    • Location: Your location
    • Biography: Brief description
  3. Appearance Settings:

    • Language: Select from 18+ supported languages (English, German, Hindi, Italian, Polish, Portuguese, etc.)
    • Theme: Light, dark, or auto (system preference)
  4. Notification Settings:

    • Email Notifications: Configure which events trigger emails
    • Web Notifications: Enable browser notifications
    • Watching: Auto-watch repositories you create or contribute to

Repository Settings

Configure individual repository settings:

  1. Navigate to your repository → Settings

  2. General:

    • Repository name, description, website
    • Visibility (public/private)
    • Template repository
    • Archive repository
  3. Features:

    • Enable/disable issues, wiki, projects, actions
    • External wiki URL
    • External issue tracker
  4. Collaborators:

    • Add users with specific permissions
    • Manage access levels
  5. Branches:

    • Default branch
    • Branch protection rules
    • Required status checks
  6. Webhooks:

    • Configure webhooks for external integrations

Webhooks and Integrations

Integrate GitCaddy with external services.

Creating a Webhook

  1. Navigate to Repository SettingsWebhooks

  2. Click "Add Webhook"

  3. Configure webhook:

    • Payload URL: Endpoint to receive events
    • Content Type: JSON or form-encoded
    • Secret: Optional secret for verification
    • Events: Select which events trigger the webhook
      • Push events
      • Pull request events
      • Issue events
      • Release events
      • etc.
  4. Click "Add Webhook"

Supported Integrations

GitCaddy provides pre-configured integrations for:

  • Slack: Post notifications to Slack channels
  • Discord: Send updates to Discord servers
  • Microsoft Teams: Integrate with Teams channels
  • Matrix: Connect to Matrix chat rooms
  • Telegram: Send notifications to Telegram
  • Email: Custom email notifications

Example: Slack Integration

  1. Create an incoming webhook in Slack
  2. In GitCaddy, add a Slack webhook
  3. Paste the Slack webhook URL
  4. Select events to post (push, PR, issues)
  5. Customize message format and channel

Tips and Best Practices

Repository Management

  1. Use Templates: Create repository templates for common project structures to save time
  2. Branch Protection: Always enable branch protection on main and production branches
  3. Required Reviews: Enforce at least one code review before merging pull requests
  4. Status Checks: Set up CI/CD workflows as required status checks
  5. CODEOWNERS File: Create a CODEOWNERS file to automatically request reviews from relevant team members

Issue Tracking

  1. Labels: Establish a consistent labeling system across repositories
  2. Templates: Create issue templates for bug reports, feature requests, and questions
  3. Milestones: Use milestones to track progress toward releases
  4. Project Boards: Visualize work with project boards for sprint planning
  5. Time Tracking: Estimate and track time for better project planning

Pull Requests

  1. Small PRs: Keep pull requests focused and small for easier review
  2. Descriptive Titles: Write clear, descriptive PR titles
  3. Link Issues: Always reference related issues in PR descriptions
  4. Draft PRs: Use draft pull requests for work-in-progress code
  5. Review Checklist: Create a PR template with a review checklist

CI/CD Workflows

  1. Matrix Testing: Test across multiple versions and platforms
  2. Caching: Cache dependencies to speed up workflow runs
  3. Artifacts: Upload build artifacts and test results
  4. Conditional Jobs: Use conditions to skip unnecessary jobs
  5. Secrets Management: Use Vault for sensitive credentials

Security

  1. 2FA: Require two-factor authentication for all organization members
  2. Signed Commits: Enforce GPG-signed commits for critical repositories
  3. Dependency Scanning: Set up automated dependency vulnerability scanning
  4. Secret Scanning: Enable secret scanning to prevent credential leaks
  5. Regular Audits: Review access permissions and audit logs regularly

Performance

  1. LFS for Large Files: Use Git LFS for binary files and large assets
  2. Shallow Clones: Use shallow clones in CI/CD to reduce clone time
  3. Archive Inactive Repos: Archive repositories that are no longer maintained
  4. Cleanup: Regularly clean up old branches and tags

Troubleshooting

Authentication Issues

Problem: Cannot push or pull from repository

Solutions:

  1. Verify SSH key is added to your GitCaddy account
  2. Test SSH connection: ssh -T git@gitcaddy.example.com
  3. For HTTPS, ensure you're using a personal access token, not your password
  4. Check repository permissions (you may only have read access)

Problem: 2FA code not working

Solutions:

  1. Ensure your device clock is synchronized (2FA is time-based)
  2. Try using a recovery code instead
  3. Contact an administrator to reset 2FA if locked out

Workflow Issues

Problem: GitCaddy Actions workflow not triggering

Solutions:

  1. Verify the workflow file is in .gitea/workflows/ directory
  2. Check YAML syntax (use a YAML validator)
  3. Ensure the trigger events match your actions (e.g., on: push)
  4. Check if Actions are enabled in repository settings
  5. Verify at least one runner is online and available

Problem: Workflow fails with "runner not found"

Solutions:

  1. Check runner status in SettingsActionsRunners
  2. Restart the runner service
  3. Verify runner labels match workflow requirements
  4. Check runner logs for connection issues

Repository Issues

Problem: Large repository clone is slow

Solutions:

  1. Use shallow clone: git clone --depth=1 <url>
  2. Enable Git LFS for large files
  3. Consider using sparse checkout for monorepos
  4. Check network connectivity and bandwidth

Problem: Cannot merge pull request

Solutions:

  1. Resolve merge conflicts locally and push
  2. Ensure all required status checks pass
  3. Verify you have required approvals
  4. Check branch protection rules
  5. Ensure you have write permissions

Vault Issues

Problem: Cannot access Vault secrets in workflow

Solutions:

  1. Verify access token has correct permissions
  2. Check token hasn't expired
  3. Ensure secret key name matches exactly (case-sensitive)
  4. Verify Vault is enabled for the repository/organization

Package Registry Issues

Problem: Cannot publish package

Solutions:

  1. Verify authentication credentials
  2. Check package name doesn't conflict with existing package
  3. Ensure you have write permissions to the registry
  4. Review package manifest for errors
  5. Check registry URL is correct for the package type

Problem: Cannot install package

Solutions:

  1. Verify registry URL is configured correctly
  2. Check authentication if package is private
  3. Ensure package version exists
  4. Try clearing package manager cache

Performance Issues

Problem: GitCaddy web interface is slow

Solutions:

  1. Check server resources (CPU, memory, disk)
  2. Review database performance and optimize queries
  3. Enable caching in app.ini configuration
  4. Check for large repositories causing indexing delays
  5. Review logs for errors: ./gitcaddy admin logs

Problem: Git operations are slow

Solutions:

  1. Run git gc to optimize repository
  2. Check if repository needs LFS for large files
  3. Verify network latency between client and server
  4. Consider using SSH instead of HTTPS (or vice versa)

Getting Help

If you continue to experience issues:

  1. Documentation: Check the official GitCaddy documentation
  2. Community Forum: Search or post in the community forum
  3. Issue Tracker: Report bugs in the GitCaddy repository
  4. Admin Logs: Review system logs in Site AdministrationMonitoring
  5. Support: Contact your GitCaddy administrator or support team

Useful Commands:

# Check GitCaddy version
./gitcaddy --version

# View logs
./gitcaddy admin logs

# Run diagnostics
./gitcaddy doctor

# Database maintenance
./gitcaddy admin regenerate hooks
./gitcaddy admin regenerate keys

Conclusion

GitCaddy provides a comprehensive, self-hosted solution for Git repository management with powerful features for collaboration, automation, and security. This guide has covered the essential workflows and features to help you get started and become productive quickly.

For advanced topics, enterprise features, and administrative configuration, refer to the official GitCaddy documentation or contact your system administrator.

Happy coding! 🚀

GitCaddy API Reference

Complete technical reference for developers integrating with or using GitCaddy, a self-hosted Git repository management platform.

Table of Contents

Introduction

GitCaddy provides comprehensive REST APIs for repository management, collaboration tools, CI/CD workflows, package registry, and enterprise features. All API endpoints are accessible at:

https://your-gitcaddy-instance.com/api/v1/

Base URL Format:

https://{instance}/api/v1/{endpoint}

Content Type: All requests and responses use application/json unless otherwise specified.

API Versioning: Current stable version: v1

Authentication

GitCaddy supports multiple authentication methods for API access.

Personal Access Tokens

Personal access tokens (PATs) provide programmatic access to the GitCaddy API.

Creating a Token:

  1. Navigate to User Settings → Applications → Manage Access Tokens
  2. Click "Generate New Token"
  3. Set token name and scopes
  4. Copy the generated token (shown only once)

Using Tokens:

Include the token in the Authorization header:

Authorization: token YOUR_ACCESS_TOKEN

Example Request:

curl -H "Authorization: token abc123def456" \
  https://gitcaddy.example.com/api/v1/user

Token Scopes:

Scope Description
repo Full access to repositories
repo:status Read-only access to repository status
public_repo Access to public repositories only
admin:org Full organization administration
write:org Write access to organizations
read:org Read-only organization access
admin:public_key Manage public SSH keys
admin:repo_hook Manage repository webhooks
admin:org_hook Manage organization webhooks
notification Access notifications
user Full user profile access
read:user Read-only user profile access
user:email Access user email addresses
delete_repo Delete repositories
package Access package registry
admin:gpg_key Manage GPG keys
admin:application Manage OAuth applications

OAuth2 Authentication

GitCaddy supports OAuth2 for third-party application integration.

OAuth2 Flow:

  1. Register Application:

    • User Settings → Applications → OAuth2 Applications
    • Create new OAuth2 application
    • Note client_id and client_secret
  2. Authorization Request:

GET /login/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&state={state}
  1. Token Exchange:
POST /login/oauth/access_token
Content-Type: application/json

{
  "client_id": "your_client_id",
  "client_secret": "your_client_secret",
  "code": "authorization_code",
  "grant_type": "authorization_code",
  "redirect_uri": "https://your-app.com/callback"
}

Response:

{
  "access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "token_type": "bearer",
  "scope": "repo,user"
}
  1. Using Access Token:
Authorization: Bearer gho_16C7e42F292c6912E7710c838347Ae178B4a

Supported OAuth2 Providers:

GitCaddy can authenticate users via external OAuth2 providers:

  • GitHub
  • GitLab
  • Bitbucket
  • Google
  • Microsoft Azure AD
  • Custom OpenID Connect providers

WebAuthn (Passkeys)

GitCaddy supports WebAuthn for passwordless authentication and two-factor authentication.

Registration API:

// Client-side registration
const response = await fetch('/user/settings/security/webauthn/register', {
  method: 'GET',
  credentials: 'include'
});

const options = await response.json();

// Create credential
const credential = await navigator.credentials.create({
  publicKey: options
});

// Send credential to server
await fetch('/user/settings/security/webauthn/register', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'My Security Key',
    credential: credential
  })
});

Authentication API:

// Get authentication challenge
const response = await fetch('/user/webauthn/assertion', {
  method: 'GET'
});

const options = await response.json();

// Get credential
const assertion = await navigator.credentials.get({
  publicKey: options
});

// Verify assertion
await fetch('/user/webauthn/assertion', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(assertion)
});

REST API Endpoints

Repository APIs

List User Repositories

GET /api/v1/user/repos

Parameters:

Parameter Type Required Description
page integer No Page number (default: 1)
limit integer No Page size (default: 10, max: 50)
type string No Filter by type: owner, collaborator, member

Response:

[
  {
    "id": 1,
    "owner": {
      "id": 1,
      "login": "username",
      "full_name": "User Name",
      "avatar_url": "https://gitcaddy.example.com/avatars/1"
    },
    "name": "my-repo",
    "full_name": "username/my-repo",
    "description": "Repository description",
    "private": false,
    "fork": false,
    "parent": null,
    "empty": false,
    "mirror": false,
    "size": 1024,
    "html_url": "https://gitcaddy.example.com/username/my-repo",
    "ssh_url": "git@gitcaddy.example.com:username/my-repo.git",
    "clone_url": "https://gitcaddy.example.com/username/my-repo.git",
    "website": "",
    "stars_count": 5,
    "forks_count": 2,
    "watchers_count": 3,
    "open_issues_count": 1,
    "default_branch": "main",
    "archived": false,
    "created_at": "2024-01-01T00:00:00Z",
    "updated_at": "2024-01-15T12:30:00Z",
    "permissions": {
      "admin": true,
      "push": true,
      "pull": true
    }
  }
]

Create Repository

POST /api/v1/user/repos

Request Body:

{
  "name": "new-repo",
  "description": "My new repository",
  "private": false,
  "auto_init": true,
  "gitignores": "Go",
  "license": "MIT",
  "readme": "Default",
  "default_branch": "main"
}

Parameters:

Parameter Type Required Description
name string Yes Repository name
description string No Repository description
private boolean No Create as private (default: false)
auto_init boolean No Initialize with README (default: false)
gitignores string No .gitignore template name
license string No License template (MIT, Apache-2.0, GPL-3.0, etc.)
readme string No README template
default_branch string No Default branch name (default: main)
trust_model string No Trust model: default, collaborator, committer, collaboratorcommitter

Response: 201 Created

{
  "id": 2,
  "name": "new-repo",
  "full_name": "username/new-repo",
  "private": false,
  "html_url": "https://gitcaddy.example.com/username/new-repo",
  "clone_url": "https://gitcaddy.example.com/username/new-repo.git",
  "created_at": "2024-01-20T10:00:00Z"
}

Get Repository

GET /api/v1/repos/{owner}/{repo}

Response:

{
  "id": 1,
  "owner": {
    "id": 1,
    "login": "username",
    "full_name": "User Name"
  },
  "name": "my-repo",
  "full_name": "username/my-repo",
  "description": "Repository description",
  "private": false,
  "default_branch": "main",
  "permissions": {
    "admin": true,
    "push": true,
    "pull": true
  }
}

Delete Repository

DELETE /api/v1/repos/{owner}/{repo}

Response: 204 No Content

List Repository Branches

GET /api/v1/repos/{owner}/{repo}/branches

Response:

[
  {
    "name": "main",
    "commit": {
      "id": "abc123def456",
      "message": "Initial commit",
      "url": "https://gitcaddy.example.com/username/my-repo/commit/abc123def456"
    },
    "protected": true,
    "user_can_push": true,
    "user_can_merge": true
  }
]

Create Branch

POST /api/v1/repos/{owner}/{repo}/branches

Request Body:

{
  "new_branch_name": "feature-branch",
  "old_branch_name": "main"
}

Get Branch Protection

GET /api/v1/repos/{owner}/{repo}/branch_protections/{branch}

Response:

{
  "branch_name": "main",
  "enable_push": false,
  "enable_push_whitelist": true,
  "push_whitelist_usernames": ["admin"],
  "push_whitelist_teams": ["core-team"],
  "push_whitelist_deploy_keys": false,
  "enable_merge_whitelist": true,
  "merge_whitelist_usernames": ["maintainer"],
  "merge_whitelist_teams": ["reviewers"],
  "enable_status_check": true,
  "status_check_contexts": ["ci/tests", "ci/lint"],
  "required_approvals": 2,
  "enable_approvals_whitelist": false,
  "block_on_rejected_reviews": true,
  "dismiss_stale_approvals": true,
  "require_signed_commits": true,
  "protected_file_patterns": "*.lock",
  "unprotected_file_patterns": "docs/*"
}

List Repository Tags

GET /api/v1/repos/{owner}/{repo}/tags

Response:

[
  {
    "name": "v1.0.0",
    "commit": {
      "sha": "abc123def456",
      "url": "https://gitcaddy.example.com/username/my-repo/commit/abc123def456"
    },
    "zipball_url": "https://gitcaddy.example.com/username/my-repo/archive/v1.0.0.zip",
    "tarball_url": "https://gitcaddy.example.com/username/my-repo/archive/v1.0.0.tar.gz"
  }
]

Get File Contents

GET /api/v1/repos/{owner}/{repo}/contents/{filepath}?ref={branch}

Parameters:

Parameter Type Required Description
ref string No Branch, tag, or commit SHA (default: default branch)

Response:

{
  "name": "README.md",
  "path": "README.md",
  "sha": "abc123",
  "type": "file",
  "size": 1024,
  "encoding": "base64",
  "content": "IyBNeVJlcG8KClRoaXMgaXMgYSBSRUFETUUgZmlsZS4=",
  "target": null,
  "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/contents/README.md",
  "html_url": "https://gitcaddy.example.com/username/my-repo/src/branch/main/README.md",
  "git_url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/git/blobs/abc123",
  "download_url": "https://gitcaddy.example.com/username/my-repo/raw/branch/main/README.md"
}

Create/Update File

POST /api/v1/repos/{owner}/{repo}/contents/{filepath}

Request Body:

{
  "content": "base64_encoded_content",
  "message": "Create README.md",
  "branch": "main",
  "sha": "abc123def456",
  "author": {
    "name": "Author Name",
    "email": "author@example.com"
  },
  "committer": {
    "name": "Committer Name",
    "email": "committer@example.com"
  },
  "dates": {
    "author": "2024-01-20T10:00:00Z",
    "committer": "2024-01-20T10:00:00Z"
  },
  "signoff": false,
  "new_branch": "feature-branch"
}

Parameters:

Parameter Type Required Description
content string Yes Base64-encoded file content
message string Yes Commit message
branch string No Branch name (default: default branch)
sha string No Blob SHA for update (required when updating)
new_branch string No Create new branch for commit

Delete File

DELETE /api/v1/repos/{owner}/{repo}/contents/{filepath}

Request Body:

{
  "message": "Delete file",
  "sha": "abc123def456",
  "branch": "main"
}

Fork Repository

POST /api/v1/repos/{owner}/{repo}/forks

Request Body:

{
  "organization": "my-org",
  "name": "forked-repo"
}

List Forks

GET /api/v1/repos/{owner}/{repo}/forks

Mirror Repository

POST /api/v1/repos/migrate

Request Body:

{
  "clone_addr": "https://github.com/user/repo.git",
  "auth_username": "username",
  "auth_password": "password_or_token",
  "uid": 1,
  "repo_name": "mirrored-repo",
  "mirror": true,
  "private": false,
  "description": "Mirrored repository"
}

Issue APIs

List Repository Issues

GET /api/v1/repos/{owner}/{repo}/issues

Parameters:

Parameter Type Required Description
state string No Filter by state: open, closed, all (default: open)
labels string No Comma-separated label IDs or names
q string No Search query
type string No Filter by type: issues, pulls
milestones string No Comma-separated milestone names
since string No Only issues updated after this time (ISO 8601)
before string No Only issues updated before this time (ISO 8601)
created_by string No Filter by creator username
assigned_by string No Filter by assignee username
mentioned_by string No Filter by mentioned username
page integer No Page number
limit integer No Page size

Response:

[
  {
    "id": 1,
    "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/issues/1",
    "html_url": "https://gitcaddy.example.com/username/my-repo/issues/1",
    "number": 1,
    "user": {
      "id": 1,
      "login": "username",
      "full_name": "User Name"
    },
    "title": "Bug: Application crashes on startup",
    "body": "Detailed description of the issue...",
    "labels": [
      {
        "id": 1,
        "name": "bug",
        "color": "#ee0701",
        "description": "Something isn't working"
      }
    ],
    "milestone": {
      "id": 1,
      "title": "v1.0",
      "description": "First release",
      "state": "open",
      "due_on": "2024-12-31T23:59:59Z"
    },
    "assignees": [
      {
        "id": 2,
        "login": "developer"
      }
    ],
    "state": "open",
    "is_locked": false,
    "comments": 3,
    "created_at": "2024-01-15T10:00:00Z",
    "updated_at": "2024-01-16T14:30:00Z",
    "closed_at": null,
    "due_date": null,
    "pull_request": null
  }
]

Create Issue

POST /api/v1/repos/{owner}/{repo}/issues

Request Body:

{
  "title": "New issue title",
  "body": "Issue description with **markdown** support",
  "assignees": ["developer1", "developer2"],
  "labels": [1, 2],
  "milestone": 1,
  "closed": false,
  "due_date": "2024-12-31T23:59:59Z",
  "ref": "main"
}

Response: 201 Created

Get Issue

GET /api/v1/repos/{owner}/{repo}/issues/{index}

Update Issue

PATCH /api/v1/repos/{owner}/{repo}/issues/{index}

Request Body:

{
  "title": "Updated title",
  "body": "Updated description",
  "state": "closed",
  "assignees": ["user1"],
  "labels": [1, 3],
  "milestone": 2,
  "due_date": "2024-12-31T23:59:59Z",
  "unset_due_date": false
}

List Issue Comments

GET /api/v1/repos/{owner}/{repo}/issues/{index}/comments

Response:

[
  {
    "id": 1,
    "html_url": "https://gitcaddy.example.com/username/my-repo/issues/1#issuecomment-1",
    "pull_request_url": "",
    "issue_url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/issues/1",
    "user": {
      "id": 1,
      "login": "username"
    },
    "original_author": "",
    "original_author_id": 0,
    "body": "This is a comment on the issue",
    "created_at": "2024-01-15T11:00:00Z",
    "updated_at": "2024-01-15T11:00:00Z"
  }
]

Create Issue Comment

POST /api/v1/repos/{owner}/{repo}/issues/{index}/comments

Request Body:

{
  "body": "Comment text with **markdown** support"
}

Edit Issue Comment

PATCH /api/v1/repos/{owner}/{repo}/issues/comments/{id}

Delete Issue Comment

DELETE /api/v1/repos/{owner}/{repo}/issues/comments/{id}

List Issue Labels

GET /api/v1/repos/{owner}/{repo}/labels

Response:

[
  {
    "id": 1,
    "name": "bug",
    "color": "#ee0701",
    "description": "Something isn't working",
    "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/labels/1"
  }
]

Create Label

POST /api/v1/repos/{owner}/{repo}/labels

Request Body:

{
  "name": "enhancement",
  "color": "#a2eeef",
  "description": "New feature or request"
}

Track Time on Issue

POST /api/v1/repos/{owner}/{repo}/issues/{index}/times

Request Body:

{
  "time": 3600,
  "created": "2024-01-15T10:00:00Z",
  "user_name": "username"
}

Parameters:

Parameter Type Required Description
time integer Yes Time in seconds
created string No Timestamp (ISO 8601)
user_name string No Username (admin only)

List Tracked Times

GET /api/v1/repos/{owner}/{repo}/issues/{index}/times

Pull Request APIs

List Pull Requests

GET /api/v1/repos/{owner}/{repo}/pulls

Parameters:

Parameter Type Required Description
state string No Filter by state: open, closed, all
sort string No Sort by: oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority
milestone integer No Filter by milestone ID
labels string No Comma-separated label IDs
page integer No Page number
limit integer No Page size

Response:

[
  {
    "id": 1,
    "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/pulls/1",
    "number": 1,
    "user": {
      "id": 1,
      "login": "contributor"
    },
    "title": "Add new feature",
    "body": "This PR adds a new feature...",
    "labels": [],
    "milestone": null,
    "assignees": [],
    "state": "open",
    "is_locked": false,
    "comments": 2,
    "html_url": "https://gitcaddy.example.com/username/my-repo/pulls/1",
    "diff_url": "https://gitcaddy.example.com/username/my-repo/pulls/1.diff",
    "patch_url": "https://gitcaddy.example.com/username/my-repo/pulls/1.patch",
    "mergeable": true,
    "merged": false,
    "merged_at": null,
    "merge_commit_sha": null,
    "merged_by": null,
    "base": {
      "label": "main",
      "ref": "main",
      "sha": "abc123",
      "repo_id": 1,
      "repo": {
        "id": 1,
        "name": "my-repo",
        "full_name": "username/my-repo"
      }
    },
    "head": {
      "label": "contributor:feature-branch",
      "ref": "feature-branch",
      "sha": "def456",
      "repo_id": 2,
      "repo": {
        "id": 2,
        "name": "my-repo",
        "full_name": "contributor/my-repo"
      }
    },
    "merge_base": "abc123",
    "due_date": null,
    "created_at": "2024-01-15T10:00:00Z",
    "updated_at": "2024-01-16T14:30:00Z",
    "closed_at": null
  }
]

Create Pull Request

POST /api/v1/repos/{owner}/{repo}/pulls

Request Body:

{
  "title": "Add new feature",
  "body": "Detailed description of changes",
  "head": "feature-branch",
  "base": "main",
  "assignees": ["reviewer1"],
  "labels": [1],
  "milestone": 1,
  "due_date": "2024-12-31T23:59:59Z"
}

Parameters:

Parameter Type Required Description
title string Yes PR title
body string No PR description
head string Yes Branch containing changes
base string Yes Branch to merge into
assignees array No Array of usernames
labels array No Array of label IDs
milestone integer No Milestone ID

Get Pull Request

GET /api/v1/repos/{owner}/{repo}/pulls/{index}

Update Pull Request

PATCH /api/v1/repos/{owner}/{repo}/pulls/{index}

Request Body:

{
  "title": "Updated title",
  "body": "Updated description",
  "base": "main",
  "assignees": ["reviewer1", "reviewer2"],
  "labels": [1, 2],
  "milestone": 1,
  "state": "closed",
  "due_date": "2024-12-31T23:59:59Z"
}

Merge Pull Request

POST /api/v1/repos/{owner}/{repo}/pulls/{index}/merge

Request Body:

{
  "Do": "merge",
  "MergeMessageField": "Merge pull request #1",
  "MergeTitleField": "Add new feature",
  "delete_branch_after_merge": true,
  "force_merge": false,
  "head_commit_id": "def456",
  "merge_when_checks_succeed": false
}

Parameters:

Parameter Type Required Description
Do string Yes Merge method: merge, rebase, rebase-merge, squash, manually-merged
MergeMessageField string No Merge commit message
MergeTitleField string No Merge commit title
delete_branch_after_merge boolean No Delete head branch after merge
force_merge boolean No Force merge even if checks fail
head_commit_id string No Expected head commit SHA

List PR Reviews

GET /api/v1/repos/{owner}/{repo}/pulls/{index}/reviews

Response:

[
  {
    "id": 1,
    "user": {
      "id": 2,
      "login": "reviewer"
    },
    "body": "Looks good to me!",
    "commit_id": "def456",
    "state": "APPROVED",
    "html_url": "https://gitcaddy.example.com/username/my-repo/pulls/1#pullrequestreview-1",
    "submitted_at": "2024-01-16T10:00:00Z"
  }
]

Create PR Review

POST /api/v1/repos/{owner}/{repo}/pulls/{index}/reviews

Request Body:

{
  "body": "Review comment",
  "event": "APPROVED",
  "comments": [
    {
      "path": "src/main.go",
      "body": "Consider refactoring this function",
      "old_position": 0,
      "new_position": 42
    }
  ]
}

Parameters:

Parameter Type Required Description
body string No Overall review comment
event string Yes Review state: APPROVED, REQUEST_CHANGES, COMMENT
comments array No Array of line comments

Submit PR Review

POST /api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}

Dismiss PR Review

POST /api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/dismissals

Request Body:

{
  "message": "Outdated review"
}

Request AI Code Review

POST /api/v1/repos/{owner}/{repo}/pulls/{index}/ai-review

Request Body:

{
  "provider": "openai",
  "model": "gpt-4"
}

Response:

{
  "review_id": 42,
  "status": "pending",
  "message": "AI review requested. Results will be posted as comments."
}

Organization APIs

List Organizations

GET /api/v1/orgs

Parameters:

Parameter Type Required Description
page integer No Page number
limit integer No Page size

Get Organization

GET /api/v1/orgs/{org}

Response:

{
  "id": 1,
  "username": "my-org",
  "full_name": "My Organization",
  "avatar_url": "https://gitcaddy.example.com/avatars/1",
  "description": "Organization description",
  "website": "https://example.com",
  "location": "San Francisco, CA",
  "visibility": "public",
  "repo_admin_change_team_access": false,
  "username": "my-org"
}

Create Organization

POST /api/v1/orgs

Request Body:

{
  "username": "new-org",
  "full_name": "New Organization",
  "description": "Organization description",
  "website": "https://example.com",
  "location": "San Francisco, CA",
  "visibility": "public",
  "repo_admin_change_team_access": false
}

Parameters:

Parameter Type Required Description
username string Yes Organization username
full_name string No Display name
description string No Organization description
website string No Website URL
location string No Location
visibility string No Visibility: public, limited, private

Edit Organization

PATCH /api/v1/orgs/{org}

Delete Organization

DELETE /api/v1/orgs/{org}

List Organization Teams

GET /api/v1/orgs/{org}/teams

Response:

[
  {
    "id": 1,
    "name": "core-team",
    "description": "Core development team",
    "organization": {
      "id": 1,
      "username": "my-org",
      "full_name": "My Organization"
    },
    "permission": "admin",
    "can_create_org_repo": true,
    "includes_all_repositories": false,
    "units": [
      "repo.code",
      "repo.issues",
      "repo.pulls",
      "repo.releases",
      "repo.wiki"
    ]
  }
]

Create Team

POST /api/v1/orgs/{org}/teams

Request Body:

{
  "name": "new-team",
  "description": "Team description",
  "permission": "write",
  "can_create_org_repo": false,
  "includes_all_repositories": false,
  "units": [
    "repo.code",
    "repo.issues",
    "repo.pulls"
  ]
}

Parameters:

Parameter Type Required Description
name string Yes Team name
description string No Team description
permission string No Permission level: read, write, admin
units array No Repository unit permissions

List Team Members

GET /api/v1/teams/{id}/members

Add Team Member

PUT /api/v1/teams/{id}/members/{username}

Remove Team Member

DELETE /api/v1/teams/{id}/members/{username}

List Team Repositories

GET /api/v1/teams/{id}/repos

Add Team Repository

PUT /api/v1/teams/{id}/repos/{org}/{repo}

User APIs

Get Authenticated User

GET /api/v1/user

Response:

{
  "id": 1,
  "login": "username",
  "full_name": "User Name",
  "email": "user@example.com",
  "avatar_url": "https://gitcaddy.example.com/avatars/1",
  "language": "en-US",
  "is_admin": false,
  "last_login": "2024-01-20T10:00:00Z",
  "created": "2023-01-01T00:00:00Z",
  "restricted": false,
  "active": true,
  "prohibit_login": false,
  "location": "San Francisco",
  "website": "https://example.com",
  "description": "User bio",
  "visibility": "public",
  "followers_count": 10,
  "following_count": 5,
  "starred_repos_count": 20
}

Get User

GET /api/v1/users/{username}

List User Emails

GET /api/v1/user/emails

Response:

[
  {
    "email": "user@example.com",
    "verified": true,
    "primary": true
  },
  {
    "email": "alternate@example.com",
    "verified": false,
    "primary": false
  }
]

Add Email

POST /api/v1/user/emails

Request Body:

{
  "emails": ["new@example.com"]
}

Delete Email

DELETE /api/v1/user/emails

Request Body:

{
  "emails": ["old@example.com"]
}

List SSH Keys

GET /api/v1/user/keys

Response:

[
  {
    "id": 1,
    "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
    "url": "https://gitcaddy.example.com/api/v1/user/keys/1",
    "title": "Work Laptop",
    "fingerprint": "SHA256:abc123def456",
    "created_at": "2024-01-01T00:00:00Z",
    "read_only": false
  }
]

Add SSH Key

POST /api/v1/user/keys

Request Body:

{
  "title": "My Key",
  "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC...",
  "read_only": false
}

Delete SSH Key

DELETE /api/v1/user/keys/{id}

List GPG Keys

GET /api/v1/user/gpg_keys

Response:

[
  {
    "id": 1,
    "primary_key_id": "",
    "key_id": "ABC123DEF456",
    "public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...",
    "emails": [
      {
        "email": "user@example.com",
        "verified": true
      }
    ],
    "subkeys": [],
    "can_sign": true,
    "can_encrypt_comms": true,
    "can_encrypt_storage": true,
    "can_certify": true,
    "created_at": "2024-01-01T00:00:00Z",
    "expires_at": "2025-01-01T00:00:00Z"
  }
]

Add GPG Key

POST /api/v1/user/gpg_keys

Request Body:

{
  "armored_public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n..."
}

List Starred Repositories

GET /api/v1/user/starred

Star Repository

PUT /api/v1/user/starred/{owner}/{repo}

Unstar Repository

DELETE /api/v1/user/starred/{owner}/{repo}

List Watched Repositories

GET /api/v1/user/subscriptions

Watch Repository

PUT /api/v1/repos/{owner}/{repo}/subscription

Unwatch Repository

DELETE /api/v1/repos/{owner}/{repo}/subscription

Package Registry APIs

GitCaddy supports multiple package formats with dedicated API endpoints.

List Packages

GET /api/v1/packages/{owner}

Parameters:

Parameter Type Required Description
type string No Package type: npm, maven, docker, pypi, alpine, etc.
q string No Search query
page integer No Page number
limit integer No Page size

Response:

[
  {
    "id": 1,
    "name": "my-package",
    "version": "1.0.0",
    "type": "npm",
    "owner": {
      "id": 1,
      "login": "username"
    },
    "repository": {
      "id": 1,
      "name": "my-repo",
      "full_name": "username/my-repo"
    },
    "creator": {
      "id": 1,
      "login": "username"
    },
    "html_url": "https://gitcaddy.example.com/username/-/packages/npm/my-package/1.0.0",
    "created_at": "2024-01-15T10:00:00Z"
  }
]

Get Package

GET /api/v1/packages/{owner}/{type}/{name}/{version}

Delete Package

DELETE /api/v1/packages/{owner}/{type}/{name}/{version}

NPM Package API

Configure npm registry:

npm config set registry https://gitcaddy.example.com/api/packages/{owner}/npm/
npm config set //gitcaddy.example.com/api/packages/{owner}/npm/:_authToken {token}

Publish package:

npm publish

Install package:

npm install @{owner}/{package}

Docker Registry API

Login:

docker login gitcaddy.example.com

Tag and push:

docker tag myimage gitcaddy.example.com/{owner}/{image}:{tag}
docker push gitcaddy.example.com/{owner}/{image}:{tag}

Pull:

docker pull gitcaddy.example.com/{owner}/{image}:{tag}

Maven Package API

Configure in pom.xml:

<repositories>
  <repository>
    <id>gitcaddy</id>
    <url>https://gitcaddy.example.com/api/packages/{owner}/maven</url>
  </repository>
</repositories>

<distributionManagement>
  <repository>
    <id>gitcaddy</id>
    <url>https://gitcaddy.example.com/api/packages/{owner}/maven</url>
  </repository>
</distributionManagement>

Configure authentication in ~/.m2/settings.xml:

<servers>
  <server>
    <id>gitcaddy</id>
    <username>{username}</username>
    <password>{token}</password>
  </server>
</servers>

PyPI Package API

Configure pip:

pip config set global.index-url https://gitcaddy.example.com/api/packages/{owner}/pypi/simple

Upload with twine:

twine upload --repository-url https://gitcaddy.example.com/api/packages/{owner}/pypi dist/*

Actions APIs

List Workflow Runs

GET /api/v1/repos/{owner}/{repo}/actions/runs

Parameters:

Parameter Type Required Description
status string No Filter by status: success, failure, waiting, running
event string No Filter by event: push, pull_request, schedule
actor string No Filter by actor username
branch string No Filter by branch
page integer No Page number
limit integer No Page size

Response:

{
  "total_count": 10,
  "workflow_runs": [
    {
      "id": 1,
      "name": "CI",
      "head_branch": "main",
      "head_sha": "abc123def456",
      "run_number": 42,
      "event": "push",
      "status": "completed",
      "conclusion": "success",
      "workflow_id": 1,
      "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/actions/runs/1",
      "html_url": "https://gitcaddy.example.com/username/my-repo/actions/runs/1",
      "created_at": "2024-01-20T10:00:00Z",
      "updated_at": "2024-01-20T10:05:00Z",
      "run_started_at": "2024-01-20T10:00:30Z"
    }
  ]
}

Get Workflow Run

GET /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}

Cancel Workflow Run

POST /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}/cancel

Rerun Workflow

POST /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}/rerun

List Workflow Jobs

GET /api/v1/repos/{owner}/{repo}/actions/runs/{run_id}/jobs

Response:

{
  "total_count": 3,
  "jobs": [
    {
      "id": 1,
      "run_id": 1,
      "name": "build",
      "status": "completed",
      "conclusion": "success",
      "started_at": "2024-01-20T10:00:30Z",
      "completed_at": "2024-01-20T10:03:00Z",
      "url": "https://gitcaddy.example.com/api/v1/repos/username/my-repo/actions/jobs/1",
      "html_url": "https://gitcaddy.example.com/username/my-repo/actions/runs/1/jobs/1"
    }
  ]
}

Get Job Logs

GET /api/v1/repos/{owner}/{repo}/actions/jobs/{job_id}/logs

Response: Plain text log output

List Repository Secrets

GET /api/v1/repos/{owner}/{repo}/actions/secrets

Response:

{
  "total_count": 2,
  "secrets": [
    {
      "name": "API_KEY",
      "created_at": "2024-01-15T10:00:00Z",
      "updated_at": "2024-01-15T10:00:00Z"
    }
  ]
}

Create/Update Secret

PUT /api/v1/repos/{owner}/{repo}/actions/secrets/{secret_name}

Request Body:

{
  "value": "secret_value"
}

Delete Secret

DELETE /api/v1/repos/{owner}/{repo}/actions/secrets/{secret_name}

List Runners

GET /api/v1/repos/{owner}/{repo}/actions/runners

Response:

{
  "total_count": 1,
  "runners": [
    {
      "id": 1,
      "name": "runner-1",
      "os": "linux",
      "status": "online",
      "busy": false,
      "labels": [
        {
          "id": 1,
          "name": "ubuntu-latest",
          "type": "read-only"
        }
      ]
    }
  ]
}

Register Runner

POST /api/v1/repos/{owner}/{repo}/actions/runners/registration-token

Response:

{
  "token": "RUNNER_REGISTRATION_TOKEN",
  "expires_at": "2024-01-20T11:00:00Z"
}

Vault APIs

Enterprise-grade secrets management with encryption and audit logging.

List Vault Secrets

GET /api/v1/repos/{owner}/{repo}/vault/secrets

Response:

{
  "total_count": 5,
  "secrets": [
    {
      "id": "secret-id-123",
      "name": "database_password",
      "description": "Production database password",
      "version": 3,
      "created_at": "2024-01-01T00:00:00Z",
      "updated_at": "2024-01-15T10:00:00Z",
      "created_by": {
        "id": 1,
        "login": "admin"
      },
      "last_accessed_at": "2024-01-20T09:30:00Z",
      "access_count": 42
    }
  ]
}

Create Vault Secret

POST /api/v1/repos/{owner}/{repo}/vault/secrets

Request Body:

{
  "name": "api_key",
  "description": "External API key",
  "value": "secret_value_encrypted",
  "metadata": {
    "environment": "production",
    "service": "payment-gateway"
  }
}

Response: 201 Created

{
  "id": "secret-id-456",
  "name": "api_key",
  "version": 1,
  "created_at": "2024-01-20T10:00:00Z"
}

Get Vault Secret

GET /api/v1/repos/{owner}/{repo}/vault/secrets/{secret_id}

Parameters:

Parameter Type Required Description
version integer No Specific version (default: latest)

Response:

{
  "id": "secret-id-456",
  "name": "api_key",
  "description": "External API key",
  "value": "decrypted_secret_value",
  "version": 1,
  "created_at": "2024-01-20T10:00:00Z",
  "metadata": {
    "environment": "production",
    "service": "payment-gateway"
  }
}

Update Vault Secret

PUT /api/v1/repos/{owner}/{repo}/vault/secrets/{secret_id}

Request Body:

{
  "value": "new_secret_value",
  "description": "Updated description"
}

Response:

{
  "id": "secret-id-456",
  "version": 2,
  "updated_at": "2024-01-20T11:00:00Z"
}

Delete Vault Secret

DELETE /api/v1/repos/{owner}/{repo}/vault/secrets/{secret_id}

Response: 204 No Content

List Secret Versions

GET /api/v1/repos/{owner}/{repo}/vault/secrets/{secret_id}/versions

Response:

{
  "total_count": 3,
  "versions": [
    {
      "version": 3,
      "created_at": "2024-01-20T10:00:00Z",
      "created_by": {
        "id": 1,
        "login": "admin"
      }
    },
    {
      "version": 2,
      "created_at": "2024-01-15T10:00:00Z",
      "created_by": {
        "id": 1,
        "login": "admin"
      }
    }
  ]
}

Get Vault Audit Log

GET /api/v1/repos/{owner}/{repo}/vault/audit

Parameters:

Parameter Type Required Description
secret_id string No Filter by secret ID
action string No Filter by action: create, read, update, delete
user string No Filter by username
since string No Start date (ISO 8601)
before string No End date (ISO 8601)
page integer No Page number
limit integer No Page size

Response:

{
  "total_count": 100,
  "entries": [
    {
      "id": "audit-log-123",
      "secret_id": "secret-id-456",
      "secret_name": "api_key",
      "action": "read",
      "user": {
        "id": 2,
        "login": "developer"
      },
      "ip_address": "192.168.1.100",
      "user_agent": "GitCaddy-Actions/1.0",
      "timestamp": "2024-01-20T10:30:00Z",
      "success": true
    }
  ]
}

Generate CI/CD Token

POST /api/v1/repos/{owner}/{repo}/vault/tokens

Request Body:

{
  "name": "ci-token",
  "secret_ids": ["secret-id-456", "secret-id-789"],
  "expires_at": "2024-12-31T23:59:59Z",
  "read_only": true
}

Response:

{
  "token": "vault_token_abc123def456",
  "expires_at": "2024-12-31T23:59:59Z"
}

Git Protocol

GitCaddy supports standard Git protocols for repository operations.

HTTP(S) Protocol

Clone:

git clone https://gitcaddy.example.com/username/repo.git

Authentication:

Use personal access token as password:

git clone https://username:token@gitcaddy.example.com/username/repo.git

Or configure credential helper:

git config --global credential.helper store
git clone https://gitcaddy.example.com/username/repo.git
# Enter username and token when prompted

SSH Protocol

Clone:

git clone git@gitcaddy.example.com:username/repo.git

Setup:

  1. Generate SSH key:
ssh-keygen -t ed25519 -C "your_email@example.com"
  1. Add public key to GitCaddy:

    • User Settings → SSH/GPG Keys → Add Key
    • Paste contents of ~/.ssh/id_ed25519.pub
  2. Configure SSH:

# ~/.ssh/config
Host gitcaddy.example.com
  User git
  IdentityFile ~/.ssh/id_ed25519

Git LFS

Enable LFS for repository:

git lfs install
git lfs track "*.psd"
git add .gitattributes
git commit -m "Enable LFS for PSD files"

Configuration:

GitCaddy automatically handles LFS objects when pushing/pulling.

LFS API Endpoints:

POST /api/v1/repos/{owner}/{repo}/lfs/objects/batch

Request Body:

{
  "operation": "upload",
  "transfers": ["basic"],
  "objects": [
    {
      "oid": "abc123def456...",
      "size": 1048576
    }
  ]
}

WebSocket APIs

GitCaddy uses WebSocket connections for real-time features.

EventSource (Server-Sent Events)

Time Tracking Updates:

const eventSource = new EventSource('/user/events');

eventSource.addEventListener('timetrack', (event) => {
  const data = JSON.parse(event.data);
  console.log('Time tracking update:', data);
  // Update stopwatch UI
});

eventSource.addEventListener('error', (error) => {
  console.error('EventSource error:', error);
});

Notification Updates:

const notificationSource = new EventSource('/api/v1/notifications/events');

notificationSource.addEventListener('notification', (event) => {
  const notification = JSON.parse(event.data);
  console.log('New notification:', notification);
  // Display notification toast
});

SharedWorker

Shared stopwatch across tabs:

// Initialize shared worker for time tracking
const worker = new SharedWorker('/assets/js/stopwatch-worker.js');

worker.port.start();

worker.port.postMessage({
  action: 'start',
  issueId: 123
});

worker.port.onmessage = (event) => {
  const { action, elapsed } = event.data;
  if (action === 'tick') {
    updateStopwatchDisplay(elapsed);
  }
};

Frontend JavaScript APIs

GitCaddy provides modular JavaScript APIs for frontend functionality.

Core Utilities

DOM Manipulation

import {$, $$} from './modules/utils/dom.js';

// Select single element
const button = $('#submit-button');

// Select multiple elements
const listItems = $$('.list-item');

// Event delegation
$(document).on('click', '.dynamic-button', (event) => {
  console.log('Button clicked:', event.target);
});

HTML Escaping

import {htmlEscape} from './modules/utils/html.js';

const userInput = '<script>alert("xss")</script>';
const safe = htmlEscape(userInput);
// Result: &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;

Date/Time Utilities

import {parseISODateTime, formatDatetime} from './modules/utils/time.js';

const date = parseISODateTime('2024-01-20T10:00:00Z');
const formatted = formatDatetime(date, 'short'); // "Jan 20, 2024"

Color Utilities

import {useLightTextOnBackground} from './modules/utils/color.js';

const bgColor = '#ff0000';
const useLight = useLightTextOnBackground(bgColor);
// Returns true if light text should be used on this background

Glob Pattern Matching

import {matchGlobPattern} from './modules/utils/glob.js';

const pattern = '*.js';
const filename = 'script.js';
const matches = matchGlobPattern(pattern, filename); // true

DOM Manipulation

Creating Elements

import {createElementFromHTML} from './modules/utils/dom.js';

const html = '<div class="alert">Message</div>';
const element = createElementFromHTML(html);
document.body.appendChild(element);

Toggle Classes

import {toggleClass} from './modules/utils/dom.js';

const element = $('#my-element');
toggleClass(element, 'active', true); // Add class
toggleClass(element, 'hidden', false); // Remove class

Web Components

Absolute Date Component

<absolute-date date="2024-01-20T10:00:00Z" format="short"></absolute-date>

JavaScript API:

const dateElement = document.querySelector('absolute-date');
dateElement.setAttribute('date', '2024-01-21T12:00:00Z');

Origin URL Component

<origin-url data-url="https://example.com/page"></origin-url>

Displays sanitized origin URL with proper formatting.

Overflow Menu Component

<overflow-menu>
  <button class="item">Action 1</button>
  <button class="item">Action 2</button>
  <button class="item">Action 3</button>
</overflow-menu>

Automatically creates overflow menu for items that don't fit.

Vue Components

File Tree Component

import {createApp} from 'vue';
import FileTreeView from './modules/features/repo-file-tree.js';

const app = createApp({
  components: {
    FileTreeView
  },
  data() {
    return {
      files: [
        {name: 'src', type: 'dir', children: [...]},
        {name: 'README.md', type: 'file'}
      ]
    };
  }
});

app.mount('#file-tree');

Template:

<file-tree-view :files="files" @file-click="handleFileClick"></file-tree-view>

Context Popup Component

import {createContextPopup} from './modules/features/context-popup.js';

const popup = createContextPopup({
  items: [
    {label: 'Edit', action: () => console.log('Edit')},
    {label: 'Delete', action: () => console.log('Delete')}
  ],
  position: {x: event.clientX, y: event.clientY}
});

popup.show();

Tooltip System

import {createTippy} from './modules/features/tippy.js';

// Simple tooltip
createTippy('#my-element', {
  content: 'Tooltip text'
});

// HTML content
createTippy('.help-icon', {
  content: '<strong>Help:</strong> This is help text',
  allowHTML: true
});

// Interactive tooltip
createTippy('.interactive', {
  content: document.querySelector('#tooltip-content'),
  interactive: true,
  trigger: 'click'
});

Toast Notifications

import {showToast} from './modules/features/toast.js';

// Success toast
showToast('Operation completed successfully', 'success');

// Error toast
showToast('An error occurred', 'error');

// Warning toast
showToast('Please review your changes', 'warning');

// Info toast
showToast('New version available', 'info');

// Custom duration
showToast('Auto-closing in 5 seconds', 'info', 5000);

Markdown Rendering

import {renderMarkdown} from './modules/features/markup.js';

const markdown = '# Heading\n\nParagraph with **bold** text.';
const html = await renderMarkdown(markdown);
document.querySelector('#content').innerHTML = html;

Features:

  • GitHub-flavored markdown
  • Syntax highlighting
  • Math rendering (KaTeX)
  • Mermaid diagrams
  • Task lists
  • Emoji support

Mermaid Diagrams

import {renderMermaid} from './modules/features/mermaid.js';

const diagramCode = `
graph TD
  A[Start] --> B[Process]
  B --> C[End]
`;

await renderMermaid('#diagram-container', diagramCode);

SortableJS Integration

import Sortable from 'sortablejs';

const projectBoard = document.querySelector('#project-board');

Sortable.create(projectBoard, {
  animation: 150,
  handle: '.card-handle',
  onEnd: (event) => {
    const cardId = event.item.dataset.cardId;
    const newPosition = event.newIndex;
    
    // Update card position via API
    fetch(`/api/v1/projects/cards/${cardId}/move`, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({position: newPosition})
    });
  }
});

Error Codes

GitCaddy uses standard HTTP status codes with detailed error responses.

HTTP Status Codes

Code Status Description
200 OK Request succeeded
201 Created Resource created successfully
204 No Content Request succeeded with no response body
400 Bad Request Invalid request parameters
401 Unauthorized Authentication required
403 Forbidden Insufficient permissions
404 Not Found Resource not found
409 Conflict Resource conflict (e.g., duplicate name)
422 Unprocessable Entity Validation error
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error
503 Service Unavailable Service temporarily unavailable

Error Response Format

{
  "message": "Human-readable error message",
  "errors": [
    {
      "field": "email",
      "message": "Email is required"
    }
  ],
  "url": "https://docs.gitcaddy.example.com/api/errors/validation"
}

Common Error Codes

Authentication Errors:

{
  "message": "Unauthorized: Invalid or expired token",
  "code": "INVALID_TOKEN"
}

Validation Errors:

{
  "message": "Validation failed",
  "errors": [
    {
      "field": "name",
      "message": "Repository name already exists"
    },
    {
      "field": "description",
      "message": "Description must be less than 500 characters"
    }
  ]
}

Permission Errors:

{
  "message": "Forbidden: You do not have permission to perform this action",
  "required_permission": "admin"
}

Rate Limit Errors:

{
  "message": "API rate limit exceeded",
  "limit": 5000,
  "remaining": 0,
  "reset": "2024-01-20T11:00:00Z"
}

Resource Not Found:

{
  "message": "Repository not found",
  "resource": "repository",
  "id": "username/nonexistent-repo"
}

Rate Limiting

GitCaddy implements rate limiting to prevent abuse.

Rate Limit Headers

All API responses include rate limit information:

X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4999
X-RateLimit-Reset: 1705750800
Header Description
X-RateLimit-Limit Maximum requests per hour
X-RateLimit-Remaining Remaining requests in current window
X-RateLimit-Reset Unix timestamp when limit resets

Rate Limits by Authentication

Authentication Requests/Hour
Unauthenticated 60
Authenticated (PAT) 5,000
OAuth Application 5,000
Enterprise License 15,000

Handling Rate Limits

async function makeAPIRequest(url) {
  const response = await fetch(url, {
    headers: {
      'Authorization': 'token YOUR_TOKEN'
    }
  });
  
  const remaining = response.headers.get('X-RateLimit-Remaining');
  const reset = response.headers.get('X-RateLimit-Reset');
  
  if (response.status === 429) {
    const resetDate = new Date(reset * 1000);
    const waitTime = resetDate - new Date();
    
    console.log(`Rate limited. Retry after ${waitTime}ms`);
    await new Promise(resolve => setTimeout(resolve, waitTime));
    return makeAPIRequest(url); // Retry
  }
  
  if (remaining < 100) {
    console.warn(`Low rate limit: ${remaining} requests remaining`);
  }
  
  return response.json();
}

Webhooks

GitCaddy can send HTTP POST requests to external URLs when events occur.

Creating Webhooks

Via API:

POST /api/v1/repos/{owner}/{repo}/hooks

Request Body:

{
  "type": "gitea",
  "config": {
    "url": "https://example.com/webhook",
    "content_type": "json",
    "secret": "webhook_secret"
  },
  "events": [
    "push",
    "pull_request",
    "issues",
    "issue_comment",
    "release"
  ],
  "active": true
}

Parameters:

Parameter Type Required Description
type string Yes Webhook type: gitea, gogs, slack, discord
config.url string Yes Webhook URL
config.content_type string No Content type: json, form
config.secret string No Secret for signature verification
events array Yes Events to trigger webhook
active boolean No Enable webhook (default: true)

Webhook Events

Event Description
push Git push to repository
create Branch or tag created
delete Branch or tag deleted
fork Repository forked
issues Issue opened, closed, edited
issue_comment Comment on issue
pull_request PR opened, closed, merged, edited
pull_request_review PR review submitted
pull_request_review_comment Comment on PR review
release Release published
repository Repository created, deleted
wiki Wiki page created, edited

Webhook Payload

Push Event:

{
  "ref": "refs/heads/main",
  "before": "abc123def456",
  "after": "def456ghi789",
  "compare_url": "https://gitcaddy.example.com/username/repo/compare/abc123...def456",
  "commits": [
    {
      "id": "def456ghi789",
      "message": "Fix bug in authentication",
      "url": "https://gitcaddy.example.com/username/repo/commit/def456ghi789",
      "author": {
        "name": "Developer",
        "email": "dev@example.com",
        "username": "developer"
      },
      "committer": {
        "name": "Developer",
        "email": "dev@example.com",
        "username": "developer"
      },
      "timestamp": "2024-01-20T10:00:00Z",
      "added": ["new-file.js"],
      "removed": [],
      "modified": ["existing-file.js"]
    }
  ],
  "repository": {
    "id": 1,
    "name": "repo",
    "full_name": "username/repo",
    "html_url": "https://gitcaddy.example.com/username/repo",
    "private": false,
    "owner": {
      "id": 1,
      "login": "username",
      "full_name": "User Name"
    }
  },
  "pusher": {
    "id": 1,
    "login": "username",
    "full_name": "User Name"
  },
  "sender": {
    "id": 1,
    "login": "username",
    "full_name": "User Name"
  }
}

Pull Request Event:

{
  "action": "opened",
  "number": 1,
  "pull_request": {
    "id": 1,
    "number": 1,
    "user": {
      "id": 2,
      "login": "contributor"
    },
    "title": "Add new feature",
    "body": "Description of changes",
    "state": "open",
    "html_url": "https://gitcaddy.example.com/username/repo/pulls/1",
    "diff_url": "https://gitcaddy.example.com/username/repo/pulls/1.diff",
    "patch_url": "https://gitcaddy.example.com/username/repo/pulls/1.patch",
    "merged": false,
    "mergeable": true,
    "base": {
      "label": "main",
      "ref": "main",
      "sha": "abc123"
    },
    "head": {
      "label": "contributor:feature",
      "ref": "feature",
      "sha": "def456"
    },
    "created_at": "2024-01-20T10:00:00Z",
    "updated_at": "2024-01-20T10:00:00Z"
  },
  "repository": {
    "id": 1,
    "name": "repo",
    "full_name": "username/repo"
  },
  "sender": {
    "id": 2,
    "login": "contributor"
  }
}

Webhook Security

Signature Verification:

GitCaddy signs webhook payloads with HMAC-SHA256 using the configured secret.

X-Gitea-Signature: sha256=abc123def456...

Verification Example (Node.js):

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(payload);
  const calculatedSignature = 'sha256=' + hmac.digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(calculatedSignature)
  );
}

// Express middleware
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-gitea-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  res.status(200).send('OK');
});

Testing Webhooks

Manual Test:

curl -X POST https://gitcaddy.example.com/api/v1/repos/username/repo/hooks/1/test \
  -H "Authorization: token YOUR_TOKEN"

View Webhook Deliveries:

GET /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries

Response:

[
  {
    "id": 1,
    "uuid": "abc-123-def-456",
    "url": "https://example.com/webhook",
    "request": {
      "headers": {
        "Content-Type": "application/json",
        "X-Gitea-Event": "push",
        "X-Gitea-Signature": "sha256=..."
      },
      "body": "{...}"
    },
    "response": {
      "status": 200,
      "headers": {},
      "body": "OK"
    },
    "delivered_at": "2024-01-20T10:00:00Z",
    "duration": 0.123
  }
]

Code Examples

Complete Repository Workflow

// Create repository
async function createRepository(name, description) {
  const response = await fetch('https://gitcaddy.example.com/api/v1/user/repos', {
    method: 'POST',
    headers: {
      'Authorization': 'token YOUR_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: name,
      description: description,
      private: false,
      auto_init: true,
      license: 'MIT'
    })
  });
  
  return response.json();
}

// Add file to repository
async function addFile(owner, repo, path, content, message) {
  const encodedContent = btoa(content);
  
  const response = await fetch(
    `https://gitcaddy.example.com/api/v1/repos/${owner}/${repo}/contents/${path}`,
    {
      method: 'POST',
      headers: {
        'Authorization': 'token YOUR_TOKEN',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        content: encodedContent,
        message: message,
        branch: 'main'
      })
    }
  );
  
  return response.json();
}

// Create pull request
async function createPullRequest(owner, repo, title, head, base) {
  const response = await fetch(
    `https://gitcaddy.example.com/api/v1/repos/${owner}/${repo}/pulls`,
    {
      method: 'POST',
      headers: {
        'Authorization': 'token YOUR_TOKEN',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        title: title,
        head: head,
        base: base,
        body: 'Please review these changes'
      })
    }
  );
  
  return response.json();
}

// Usage
(async () => {
  const repo = await createRepository('my-project', 'My awesome project');
  console.log('Repository created:', repo.html_url);
  
  const file = await addFile(
    'username',
    'my-project',
    'src/index.js',
    'console.log("Hello World");',
    'Add index.js'
  );
  console.log('File added:', file.commit.sha);
  
  const pr = await createPullRequest(
    'username',
    'my-project',
    'Add feature',
    'feature-branch',
    'main'
  );
  console.log('Pull request created:', pr.html_url);
})();

Issue Management

import requests

class GitCaddyClient:
    def __init__(self, base_url, token):
        self.base_url = base_url
        self.headers = {
            'Authorization': f'token {token}',
            'Content-Type': 'application/json'
        }
    
    def create_issue(self, owner, repo, title, body, labels=None):
        url = f'{self.base_url}/api/v1/repos/{owner}/{repo}/issues'
        data = {
            'title': title,
            'body': body
        }
        if labels:
            data['labels'] = labels
        
        response = requests.post(url, json=data, headers=self.headers)
        return response.json()
    
    def add_comment(self, owner, repo, issue_number, comment):
        url = f'{self.base_url}/api/v1/repos/{owner}/{repo}/issues/{issue_number}/comments'
        data = {'body': comment}
        
        response = requests.post(url, json=data, headers=self.headers)
        return response.json()
    
    def close_issue(self, owner, repo, issue_number):
        url = f'{self.base_url}/api/v1/repos/{owner}/{repo}/issues/{issue_number}'
        data = {'state': 'closed'}
        
        response = requests.patch(url, json=data, headers=self.headers)
        return response.json()
    
    def track_time(self, owner, repo, issue_number, seconds):
        url = f'{self.base_url}/api/v1/repos/{owner}/{repo}/issues/{issue_number}/times'
        data = {'time': seconds}
        
        response = requests.post(url, json=data, headers=self.headers)
        return response.json()

# Usage
client = GitCaddyClient('https://gitcaddy.example.com', 'YOUR_TOKEN')

# Create issue
issue = client.create_issue(
    'username',
    'my-repo',
    'Bug: Login not working',
    'Users cannot log in with correct credentials',
    labels=[1, 2]  # bug, high-priority
)
print(f'Issue created: #{issue["number"]}')

# Add comment
comment = client.add_comment(
    'username',
    'my-repo',
    issue['number'],
    'Investigating the issue...'
)

# Track time (2 hours)
time_entry = client.track_time('username', 'my-repo', issue['number'], 7200)
print(f'Tracked {time_entry["time"]}s')

# Close issue
closed = client.close_issue('username', 'my-repo', issue['number'])
print(f'Issue closed: {closed["state"]}')

CI/CD Integration

# .gitcaddy/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Get secrets from Vault
        id: vault
        uses: actions/vault-secrets@v1
        with:
          secrets: |
            database_password
            api_key
      
      - name: Deploy
        if: github.ref == 'refs/heads/main'
        run: |
          echo "Deploying with API key: ${{ steps.vault.outputs.api_key }}"
          npm run deploy
        env:
          DATABASE_PASSWORD: ${{ steps.vault.outputs.database_password }}
          API_KEY: ${{ steps.vault.outputs.api_key }}

Webhook Handler

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

type PushEvent struct {
    Ref        string `json:"ref"`
    Before     string `json:"before"`
    After      string `json:"after"`
    Repository struct {
        Name     string `json:"name"`
        FullName string `json:"full_name"`
    } `json:"repository"`
    Pusher struct {
        Login string `json:"login"`
    } `json:"pusher"`
    Commits []struct {
        ID      string `json:"id"`
        Message string `json:"message"`
        Author  struct {
            Name  string `json:"name"`
            Email string `json:"email"`
        } `json:"author"`
    } `json:"commits"`
}

func verifySignature(payload []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(payload)
    expectedMAC := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(signature), []byte(expectedMAC))
}

func handleWebhook(w http.ResponseWriter, r *http.Request) {
    payload, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Error reading request body", http.StatusBadRequest)
        return
    }
    defer r.Body.Close()
    
    signature := r.Header.Get("X-Gitea-Signature")
    if !verifySignature(payload, signature, "webhook_secret") {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }
    
    event := r.Header.Get("X-Gitea-Event")
    
    switch event {
    case "push":
        var pushEvent PushEvent
        if err := json.Unmarshal(payload, &pushEvent); err != nil {
            http.Error(w, "Error parsing JSON", http.StatusBadRequest)
            return
        }
        
        log.Printf("Push to %s by %s", pushEvent.Repository.FullName, pushEvent.Pusher.Login)
        log.Printf("Commits: %d", len(pushEvent.Commits))
        
        for _, commit := range pushEvent.Commits {
            log.Printf("  - %s: %s", commit.ID[:7], commit.Message)
        }
        
    case "pull_request":
        log.Printf("Pull request event received")
        
    default:
        log.Printf("Unknown event: %s", event)
    }
    
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "Webhook processed")
}

func main() {
    http.HandleFunc("/webhook", handleWebhook)
    log.Println("Webhook server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Package Publishing

#!/bin/bash
# publish-npm.sh - Publish npm package to GitCaddy registry

GITCADDY_URL="https://gitcaddy.example.com"
OWNER="username"
TOKEN="YOUR_TOKEN"

# Configure npm
npm config set registry "${GITCADDY_URL}/api/packages/${OWNER}/npm/"
npm config set "//${GITCADDY_URL#https://}/api/packages/${OWNER}/npm/:_authToken" "${TOKEN}"

# Update version
npm version patch

# Publish
npm publish

echo "Package published to GitCaddy registry"
# Dockerfile - Build and push Docker image to GitCaddy registry
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --production

COPY . .

EXPOSE 3000

CMD ["node", "server.js"]

# Build and push:
# docker build -t gitcaddy.example.com/username/myapp:latest .
# docker login gitcaddy.example.com
# docker push gitcaddy.example.com/username/myapp:latest

For additional support and documentation, visit the GitCaddy Documentation or join the community forum.

MIT License Copyright (c) 2026 gitcaddy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Description
GitCaddy fork of Gitea with enhanced capabilities for AI-friendly workflow generation
http://www.gitcaddy.com
Readme MIT 234 MiB
2026-03-07 21:12:51 +00:00
Languages
Go 80.1%
Handlebars 10.5%
TypeScript 3.5%
CSS 2.1%
JavaScript 1.7%
Other 2%