pkg-proxy/CONTRIBUTING.md

216 lines
5.5 KiB
Markdown
Raw Permalink Normal View History

2026-01-20 21:52:44 +00:00
# Contributing to git-pkgs proxy
Thank you for your interest in contributing. This document covers how to get started, the code structure, and guidelines for submitting changes.
## Development Setup
```bash
# Clone the repository
git clone https://github.com/git-pkgs/proxy.git
cd proxy
# Install dependencies
go mod download
# Run tests
go test ./...
# Build
go build -o proxy ./cmd/proxy
# Run locally
./proxy
```
## Project Structure
```
proxy/
├── cmd/
│ └── proxy/
│ └── main.go # CLI entry point
├── internal/
│ ├── config/ # Configuration loading
│ │ └── config.go
│ ├── database/ # SQLite cache metadata
│ │ ├── database.go # DB connection, open/create
│ │ ├── schema.go # Table definitions
│ │ ├── types.go # Go structs for tables
│ │ └── queries.go # CRUD operations
│ ├── storage/ # Artifact file storage
│ │ ├── storage.go # Storage interface
│ │ └── filesystem.go # Local filesystem impl
│ ├── upstream/ # Upstream registry clients
│ │ ├── fetcher.go # HTTP artifact fetching
│ │ └── resolver.go # Download URL resolution
│ ├── handler/ # Protocol handlers
│ │ ├── handler.go # Base proxy + cache logic
│ │ ├── npm.go # npm protocol
│ │ └── cargo.go # Cargo protocol
│ └── server/ # HTTP server
│ └── server.go # Router, middleware
├── docs/
│ └── architecture.md # Internal architecture
├── README.md # End user documentation
├── CONTRIBUTING.md # This file
├── go.mod
└── go.sum
```
## Architecture Overview
The proxy is built from several independent packages:
### `internal/database`
SQLite-based cache metadata. Tracks packages, versions, and artifacts. Uses `modernc.org/sqlite` for a pure-Go SQLite driver (no CGO).
Key types:
- `Package` - Package metadata (purl, ecosystem, name)
- `Version` - Version metadata (version number, integrity hash)
- `Artifact` - Cached file info (storage path, size, hash, hit count)
### `internal/storage`
Artifact file storage abstraction. Currently implements local filesystem storage. Designed to allow future backends (S3, GCS).
Interface:
```go
type Storage interface {
Store(ctx, path string, r io.Reader) (size int64, hash string, err error)
Open(ctx, path string) (io.ReadCloser, error)
Exists(ctx, path string) (bool, error)
Delete(ctx, path string) error
Size(ctx, path string) (int64, error)
UsedSpace(ctx context.Context) (int64, error)
}
```
### `internal/upstream`
Fetches artifacts from upstream registries. Two components:
- `Fetcher` - HTTP client with retries, streams artifacts
- `Resolver` - Determines download URLs for each ecosystem
### `internal/handler`
HTTP protocol handlers. Each registry protocol has its own handler:
- `NPMHandler` - npm registry protocol
- `CargoHandler` - Cargo sparse index protocol
Handlers use a shared `Proxy` type that coordinates caching.
### `internal/server`
HTTP server setup, router configuration, middleware.
### `internal/config`
Configuration loading from files, environment variables, and flags.
## Adding a New Registry
To add support for a new package registry:
1. **Add URL resolution** in `internal/upstream/resolver.go`:
```go
case "newregistry":
url = fmt.Sprintf("https://registry.example.com/%s/%s/download", name, version)
filename = fmt.Sprintf("%s-%s.tar.gz", name, version)
```
2. **Create handler** in `internal/handler/newregistry.go`:
```go
type NewRegistryHandler struct {
proxy *Proxy
proxyURL string
}
func NewNewRegistryHandler(proxy *Proxy, proxyURL string) *NewRegistryHandler {
return &NewRegistryHandler{proxy: proxy, proxyURL: proxyURL}
}
func (h *NewRegistryHandler) Routes() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("GET /{name}/{version}", h.handleDownload)
return mux
}
```
3. **Mount handler** in `internal/server/server.go`:
```go
newHandler := handler.NewNewRegistryHandler(proxy, s.cfg.BaseURL)
mux.Handle("/newregistry/", http.StripPrefix("/newregistry", newHandler.Routes()))
```
4. **Add tests** in `internal/handler/newregistry_test.go`
5. **Update documentation** in README.md
## Code Style
- Follow standard Go conventions
- Run `go fmt` before committing
- Run `go vet` to catch common issues
- Keep functions short and focused
- Write tests for new functionality
- Document exported types and functions
## Testing
Run all tests:
```bash
go test ./...
```
Run with verbose output:
```bash
go test -v ./...
```
Run specific package:
```bash
go test -v ./internal/handler/
```
Run with coverage:
```bash
go test -cover ./...
```
## Pull Request Process
1. Fork the repository
2. Create a branch for your feature (`git checkout -b feature/my-feature`)
3. Make your changes
4. Add tests for new functionality
5. Run `go test ./...` and ensure all tests pass
6. Run `go fmt ./...` and `go vet ./...`
7. Commit with a clear message
8. Push to your fork
9. Open a pull request
### Commit Messages
Write clear, concise commit messages:
```
Add PyPI registry support
- Add URL resolution for PyPI packages
- Create PyPI protocol handler
- Add tests for wheel and sdist downloads
```
## Questions?
Open an issue on GitHub if you have questions or need help getting started.