Harness Open Source (Drone/Gitness) — Structure#

Layout pattern#

Custom Monolith with Sub-module — The project uses a domain-driven flat-ish layout at the root (no top-level pkg/ or internal/), with a large app/ directory containing the primary application code and a separately declared Go module (registry/) as a workspace replace directive. This departs from Standard Go Layout in that all root-level directories are importable public packages, with encapsulation achieved through naming convention and domain cohesion rather than internal/ boundaries. The app/ directory itself uses a layered internal structure (handler → controller → service → store).

Directory map#

repositories/drone/
├── app/                   # Core application (HTTP API, controllers, services, stores)
│   ├── api/               # HTTP layer: auth middleware, handlers, controllers, openapi
│   │   ├── auth/          # Auth middleware wrappers
│   │   ├── controller/    # Business logic per domain (30+ sub-packages)
│   │   └── handler/       # HTTP handler functions per domain (30+ sub-packages)
│   ├── auth/              # Authentication (authn) and authorization (authz)
│   ├── bootstrap/         # App bootstrap / first-run initialization
│   ├── config/            # Application configuration struct
│   ├── connector/         # External connector service
│   ├── cron/              # Cron-triggered pipeline execution
│   ├── events/            # Domain event definitions (git, pullreq, pipeline, gitspace…)
│   ├── githook/           # Git server-side hook handling
│   ├── gitspace/          # Cloud Dev Environment subsystem
│   │   ├── infrastructure/ # Gitspace infra provisioning
│   │   ├── orchestrator/  # Container / IDE orchestration
│   │   ├── platformconnector/
│   │   ├── scm/           # SCM integration for gitspaces
│   │   └── secret/
│   ├── jwt/               # JWT token creation/validation
│   ├── paths/             # Path parsing utilities (repo/space paths)
│   ├── pipeline/          # CI pipeline execution subsystem
│   │   ├── canceler/      # Pipeline cancellation
│   │   ├── commit/        # Commit status reporting
│   │   ├── converter/     # Pipeline YAML conversion (Drone → Harness spec)
│   │   ├── file/          # Pipeline YAML file loading from repo
│   │   ├── manager/       # Runner manager (assigns stages to runners)
│   │   ├── resolver/      # Plugin/template resolution
│   │   ├── runner/        # In-process runner coordination
│   │   ├── scheduler/     # Stage scheduling
│   │   └── triggerer/     # Pipeline trigger evaluation
│   ├── request/           # HTTP request context helpers
│   ├── router/            # HTTP router wiring (chi-based)
│   ├── server/            # HTTP server lifecycle
│   ├── services/          # Domain services (40+ sub-packages)
│   ├── sse/               # Server-sent events for live log streaming
│   ├── store/             # Store interfaces + implementations
│   │   ├── cache/         # Redis-backed cache for space/repo lookups
│   │   ├── database/      # SQLite/Postgres SQL store implementations
│   │   └── logs/          # Log storage abstraction
│   ├── testing/           # Integration test helpers
│   ├── token/             # Access token service
│   └── url/               # URL generation service
├── audit/                 # Audit log library
├── blob/                  # Blob/object storage abstraction (S3/GCS/local)
├── cache/                 # Generic cache interface
├── charts/                # Helm chart for Kubernetes deployment
│   └── gitness/
├── cli/                   # CLI framework wiring and sub-commands
│   ├── operations/        # CLI commands: server, account, hooks, migrate, swagger, user
│   ├── provide/           # Wire providers for CLI context
│   ├── session/           # CLI session management (local credentials)
│   └── textui/            # Terminal UI helpers
├── client/                # Go HTTP client library (for API consumers / gitness CLI)
├── cmd/
│   └── gitness/           # Single binary entry point
│       ├── main.go        # CLI registration + kingpin wiring
│       ├── wire.go        # Wire injection graph (build tag: wireinject)
│       └── wire_gen.go    # Wire-generated DI code
├── contextutil/           # context.Context helpers
├── crypto/                # Cryptographic utilities
├── encrypt/               # Encryption-at-rest abstraction
├── errors/                # Typed error definitions and HTTP mapping
├── events/                # Generic event bus (Redis Streams backed)
├── git/                   # Native git operations (wraps git CLI / libgit2)
│   ├── api/               # High-level git API (commits, refs, blobs, diffs…)
│   ├── command/           # Low-level git command execution
│   ├── diff/              # Diff parsing
│   ├── hook/              # Git hook payloads
│   ├── merge/             # Merge strategy implementations
│   ├── parser/            # Git output parsers
│   ├── storage/           # Repository on-disk storage layout
│   └── types/             # Git domain types
├── http/                  # HTTP client/server utilities
├── infraprovider/         # Infrastructure provider abstraction (Docker, etc.)
├── job/                   # Background job scheduler
├── langstats/             # Language statistics computation
├── livelog/               # Live log streaming (Redis Pub/Sub)
├── lock/                  # Distributed lock abstraction
├── logging/               # Structured logging setup (zerolog)
├── profiler/              # pprof profiling integration
├── pubsub/                # Pub/Sub abstraction (Redis-backed)
├── registry/              # OCI artifact registry — separate Go module
│   ├── app/               # Registry HTTP API, controllers, handlers
│   ├── config/            # Registry-specific config
│   ├── gc/                # Garbage collection
│   ├── job/               # Registry background jobs
│   ├── services/          # Registry domain services
│   └── types/             # Registry-specific types
├── resources/             # Embedded resources (gitignore templates, licenses)
├── scripts/
│   ├── coverage/          # Coverage scripts
│   ├── license/           # License header scripts
│   └── wire/              # Wire generation scripts
├── secret/                # Secret storage abstraction
├── ssh/                   # SSH server (gliderlabs/ssh)
├── store/                 # Root-level store helpers (dbtx)
├── stream/                # Stream abstraction
├── tests/                 # Top-level load/integration tests
├── types/                 # Shared domain types (Config, User, Repo, Space…)
│   ├── check/             # Input validation helpers
│   └── enum/              # Enum types
├── version/               # Version info
└── web/                   # React/TypeScript frontend (built into binary)

Entry points#

Single binary: cmd/gitness/main.go → produces the gitness executable.

CLI commands registered via kingpin:

  • gitness server — starts the full HTTP server, SSH server, background workers, and all domain services
  • gitness migrate — runs database migrations (dbmate-based)
  • gitness user / gitness users — user management CLI commands
  • gitness account login|register|logout — account management for CLI consumers
  • gitness hooks — git server-side hook execution (called by git itself during push/fetch)
  • gitness swagger — generates/serves OpenAPI spec

There is no cmd/*/ for separate binaries; the runner (drone pipeline executor) runs as a separate process managed by the app/pipeline/runner/ package via the drone-runner-docker dependency.

Package organization#

  • Internal packages: None formally (internal/ is not used). Encapsulation is enforced via module boundaries (the registry sub-module) and code review discipline.

  • Public packages (root-level domains):

    • audit/ — audit log emission
    • blob/ — object storage (S3/GCS/local filesystem)
    • cache/ — generic cache interface
    • encrypt/ — encryption-at-rest interface
    • errors/ — typed errors with HTTP status mapping
    • events/ — Redis Streams event bus with typed topic routing
    • git/ — native git operations (the platform’s core capability)
    • http/ — HTTP utilities (middleware, response writers)
    • infraprovider/ — Docker/VM infrastructure abstraction
    • job/ — background job scheduler
    • livelog/ — live log streaming
    • lock/ — distributed mutex
    • pubsub/ — pub/sub messaging
    • secret/ — secret storage abstraction
    • ssh/ — SSH server
    • store/ — database transaction helper (dbtx)
    • stream/ — byte stream abstraction
    • types/ — shared canonical domain types (Config, User, Repo, Space, Pipeline…)
    • version/ — version string
  • app/ internal layering (domain-driven, 3-tier):

    1. app/api/handler/ — HTTP handlers (decode request, call controller, encode response)
    2. app/api/controller/ — Business logic layer (auth checks, orchestration, domain rules)
    3. app/services/ — Domain services (cross-controller logic: merge, protection, webhooks…)
    4. app/store/ — Data access layer (interfaces in app/store/, SQL in app/store/database/)
  • registry/ sub-module: Separately versioned Go module (github.com/harness/gitness/registry) included via replace directive. Contains its own layered app/, services/, types/ structure mirroring the root layout.

  • Layering: Follows a clean layered architecture within app/. The outer layers (handler) depend on inner layers (controller/service), but cross-domain service-to-service calls happen via injected interfaces, not direct package imports. The root-level packages (git/, events/, lock/, etc.) form a shared infrastructure layer imported by app/.

Build system#

  • Build tool: make (primary), with wire for DI code generation and dbmate for migrations.
  • Key targets:
    • make build — runs wire codegen then go build -o ./gitness ./cmd/gitness
    • make test — runs all tests excluding registry conformance tests
    • make web-build — builds the React frontend (yarn install && yarn build)
    • make generate — runs go generate (wire + protobuf)
    • make run — builds and runs the server with .local.env config
    • make tools — installs linting/formatting/codegen tools (golangci-lint, wire, dbmate, etc.)
  • Docker: Yes, multi-stage:
    • Stage 1 (web): Node 16, builds React frontend with yarn
    • Stage 2 (builder): Go 1.25.8 Alpine, compiles the binary with frontend dist embedded
    • Final stage: minimal runtime image
    • Also Dockerfile.uiv2 for the v2 UI variant

Notable structural decisions#

  1. No internal/ package. With 2,500+ Go files, the project deliberately avoids internal/ in favor of domain-named root packages. This makes the entire codebase importable as a library and enables the registry sub-module to import root packages cleanly. The tradeoff is weaker access control.

  2. Single binary, maximum domain breadth. The cmd/gitness/ entry point wires 100+ WireSets into a single binary that serves as a git host, CI runner manager, artifact registry, SSH server, and cloud dev environment platform simultaneously. This is unusual even for monoliths of this size.

  3. Google Wire at scale. The wire.go file lists ~120 WireSets in a single wire.Build() call — one of the largest Wire graphs in the Go open source ecosystem. The generated wire_gen.go is hundreds of lines of auto-generated constructor call chains. This makes the DI graph explicit and compile-time verified, but the wire.go file itself is unwieldy.

  4. registry/ as a workspace sub-module. The OCI artifact registry lives in registry/ with its own go.mod, connected to the parent via a replace directive. This provides module isolation (the registry team can evolve its API surface independently) while still compiling to the same binary. It mirrors how large monorepos use Go workspaces.

  5. Event-driven cross-domain communication. Rather than direct service-to-service calls for cross-domain operations (e.g., git push triggering CI), the platform uses a Redis Streams event bus (events/). Domain events are defined per-domain in app/events/<domain>/, decoupling the git subsystem from the pipeline subsystem at runtime.

  6. Embedded frontend. The React/TypeScript frontend (web/dist/) is embedded into the Go binary at compile time using //go:embed. The web/ directory is built separately (yarn) and the resulting dist/ is copied into the Docker build context, producing a truly self-contained single-binary deployment.