2
0

feat(plugins): add PluginRouter interface for route registration
Some checks failed
Build and Release / Build Binaries (arm64, darwin, macos) (push) Has been cancelled
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Has been cancelled
Build and Release / Build Binary (linux/arm64) (push) Has been cancelled
Build and Release / Lint (push) Has been cancelled
Build and Release / Unit Tests (push) Has been cancelled
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Has been cancelled
Build and Release / Build Binaries (amd64, darwin, macos) (push) Has been cancelled
Build and Release / Create Release (push) Has been cancelled
Build and Release / Integration Tests (PostgreSQL) (push) Has been cancelled

Introduce PluginRouter interface to standardize plugin route registration and replace the previous 'any' type approach. Add WebRouterAdapter to wrap web.Router and handle path prefixes correctly. This provides a cleaner, type-safe API for plugins to register routes without needing to know about the underlying router implementation.
This commit is contained in:
2026-01-21 10:35:56 -05:00
parent 9510d0d13c
commit 015318aa0a
3 changed files with 97 additions and 8 deletions

View File

@@ -61,12 +61,12 @@ type RepoRoutesPlugin interface {
Plugin
// RegisterRepoWebRoutes adds routes under /{owner}/{repo}/
// The router is a *web.Router from the gitcaddy server
RegisterRepoWebRoutes(m any)
// The router is a PluginRouter that handles path prefixes correctly
RegisterRepoWebRoutes(r PluginRouter)
// RegisterRepoAPIRoutes adds routes under /api/v1/repos/{owner}/{repo}/
// The router is a *web.Router from the gitcaddy server
RegisterRepoAPIRoutes(m any)
// The router is a PluginRouter that handles path prefixes correctly
RegisterRepoAPIRoutes(r PluginRouter)
}
// LicensedPlugin is implemented by plugins that require a license

View File

@@ -151,27 +151,35 @@ func RegisterAPIRoutes(m any) {
}
// RegisterRepoWebRoutes registers per-repository web routes from all plugins
func RegisterRepoWebRoutes(m any) {
// The router parameter should implement WebRouter (e.g., *web.Router)
func RegisterRepoWebRoutes(router WebRouter) {
registryLock.RLock()
defer registryLock.RUnlock()
// Create adapter with empty prefix (routes are relative to current group)
adapter := NewWebRouterAdapter(router, "")
for name, p := range registry {
if rp, ok := p.(RepoRoutesPlugin); ok {
log.Debug("Registering repo web routes for plugin: %s", name)
rp.RegisterRepoWebRoutes(m)
rp.RegisterRepoWebRoutes(adapter)
}
}
}
// RegisterRepoAPIRoutes registers per-repository API routes from all plugins
func RegisterRepoAPIRoutes(m any) {
// The router parameter should implement WebRouter (e.g., *web.Router)
func RegisterRepoAPIRoutes(router WebRouter) {
registryLock.RLock()
defer registryLock.RUnlock()
// Create adapter with empty prefix (routes are relative to current group)
adapter := NewWebRouterAdapter(router, "")
for name, p := range registry {
if rp, ok := p.(RepoRoutesPlugin); ok {
log.Debug("Registering repo API routes for plugin: %s", name)
rp.RegisterRepoAPIRoutes(m)
rp.RegisterRepoAPIRoutes(adapter)
}
}
}

81
modules/plugins/router.go Normal file
View File

@@ -0,0 +1,81 @@
// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT
package plugins
import (
"net/http"
)
// PluginRouter is the interface plugins use to register routes.
// It abstracts away the underlying router implementation and ensures
// routes are registered with the correct path prefixes.
type PluginRouter interface {
// Get registers a GET route
Get(pattern string, handler http.HandlerFunc)
// Post registers a POST route
Post(pattern string, handler http.HandlerFunc)
// Put registers a PUT route
Put(pattern string, handler http.HandlerFunc)
// Delete registers a DELETE route
Delete(pattern string, handler http.HandlerFunc)
// Group creates a sub-router with a path prefix
Group(pattern string, fn func(PluginRouter))
}
// WebRouterAdapter wraps a web.Router to implement PluginRouter.
// This adapter ensures routes are registered with the correct path prefixes.
type WebRouterAdapter struct {
router WebRouter
pathPrefix string
}
// WebRouter is the interface that web.Router implements
type WebRouter interface {
Get(pattern string, h ...any)
Post(pattern string, h ...any)
Put(pattern string, h ...any)
Delete(pattern string, h ...any)
Group(pattern string, fn func(), middlewares ...any)
}
// NewWebRouterAdapter creates a new adapter for the given web.Router
func NewWebRouterAdapter(router WebRouter, pathPrefix string) *WebRouterAdapter {
return &WebRouterAdapter{
router: router,
pathPrefix: pathPrefix,
}
}
// Get implements PluginRouter.Get
func (a *WebRouterAdapter) Get(pattern string, handler http.HandlerFunc) {
a.router.Get(a.pathPrefix+pattern, handler)
}
// Post implements PluginRouter.Post
func (a *WebRouterAdapter) Post(pattern string, handler http.HandlerFunc) {
a.router.Post(a.pathPrefix+pattern, handler)
}
// Put implements PluginRouter.Put
func (a *WebRouterAdapter) Put(pattern string, handler http.HandlerFunc) {
a.router.Put(a.pathPrefix+pattern, handler)
}
// Delete implements PluginRouter.Delete
func (a *WebRouterAdapter) Delete(pattern string, handler http.HandlerFunc) {
a.router.Delete(a.pathPrefix+pattern, handler)
}
// Group implements PluginRouter.Group
func (a *WebRouterAdapter) Group(pattern string, fn func(PluginRouter)) {
subAdapter := &WebRouterAdapter{
router: a.router,
pathPrefix: a.pathPrefix + pattern,
}
fn(subAdapter)
}