feat: Rebrand to GitCaddy and add AI learning tools docs
This commit is contained in:
321
README.md
321
README.md
@@ -1,133 +1,188 @@
|
||||
# Gitea MCP Server
|
||||
|
||||
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that enables AI assistants like Claude to interact directly with your Gitea instance.
|
||||
|
||||
## Features
|
||||
|
||||
- **Query Runners** - List runners, check status, view capabilities (OS, tools, disk space)
|
||||
- **Monitor Workflows** - List runs, get job details, view logs
|
||||
- **Manage Releases** - List releases, get assets, check download counts
|
||||
- **AI-Friendly** - Structured JSON responses designed for AI consumption
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Download
|
||||
|
||||
Download the latest binary from [Releases](https://git.marketally.com/gitcaddy/mcp-server/releases).
|
||||
|
||||
### 2. Configure Claude Code
|
||||
|
||||
Add to your Claude Code settings:
|
||||
|
||||
**Option A: Command line arguments**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "/path/to/gitea-mcp-server",
|
||||
"args": ["--url", "https://git.marketally.com", "--token", "YOUR_API_TOKEN"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Option B: Environment variables**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitea": {
|
||||
"command": "/path/to/gitea-mcp-server",
|
||||
"env": {
|
||||
"GITEA_URL": "https://git.marketally.com",
|
||||
"GITEA_TOKEN": "your-token-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use It
|
||||
|
||||
Ask Claude things like:
|
||||
- "What runners are online?"
|
||||
- "Show me the latest workflow runs for gitcaddy/act_runner"
|
||||
- "Why did run #77 fail?"
|
||||
- "What assets are in the v0.3.6 release?"
|
||||
|
||||
## Available Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_runners` | List all runners with status, capabilities, disk space |
|
||||
| `get_runner` | Get detailed runner info by ID |
|
||||
| `list_workflow_runs` | List workflow runs for a repository |
|
||||
| `get_workflow_run` | Get run details with all jobs |
|
||||
| `get_job_logs` | Get logs from a specific job |
|
||||
| `list_releases` | List releases for a repository |
|
||||
| `get_release` | Get release details with all assets |
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
git clone https://git.marketally.com/gitcaddy/mcp-server.git
|
||||
cd mcp-server
|
||||
go build -o gitea-mcp-server .
|
||||
```
|
||||
|
||||
### Cross-compile for all platforms
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
GOOS=linux GOARCH=amd64 go build -o gitea-mcp-server-linux-amd64 .
|
||||
|
||||
# macOS Intel
|
||||
GOOS=darwin GOARCH=amd64 go build -o gitea-mcp-server-darwin-amd64 .
|
||||
|
||||
# macOS Apple Silicon
|
||||
GOOS=darwin GOARCH=arm64 go build -o gitea-mcp-server-darwin-arm64 .
|
||||
|
||||
# Windows
|
||||
GOOS=windows GOARCH=amd64 go build -o gitea-mcp-server-windows-amd64.exe .
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐ stdio ┌──────────────────┐ HTTP ┌─────────────┐
|
||||
│ Claude Code │ ◄────────────► │ gitea-mcp-server │ ◄───────────► │ Gitea │
|
||||
│ (AI Tool) │ JSON-RPC │ (This binary) │ /api/v2/mcp │ Server │
|
||||
└─────────────┘ └──────────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
The MCP server:
|
||||
1. Receives JSON-RPC requests over stdio from Claude Code
|
||||
2. Forwards them to Gitea's `/api/v2/mcp` endpoint
|
||||
3. Returns responses back to Claude Code
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Flag | Env Variable | Description |
|
||||
|------|-------------|-------------|
|
||||
| `--url` | `GITEA_URL` | Gitea server URL (required) |
|
||||
| `--token` | `GITEA_TOKEN` | API token for authentication |
|
||||
| `--debug` | - | Enable debug logging to stderr |
|
||||
|
||||
## Obtaining an API Token
|
||||
|
||||
1. Go to your Gitea instance → Settings → Applications
|
||||
2. Generate a new token with appropriate scopes
|
||||
3. Copy the token and use it in your configuration
|
||||
|
||||
## Requirements
|
||||
|
||||
- Gitea 1.26+ with GitCaddy enhancements (includes `/api/v2/mcp` endpoint)
|
||||
- Go 1.21+ (for building from source)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See [LICENSE](LICENSE) file.
|
||||
|
||||
## Related Projects
|
||||
|
||||
- [GitCaddy Gitea](https://git.marketally.com/gitcaddy/gitea) - Enhanced Gitea fork with AI-friendly APIs
|
||||
- [GitCaddy act_runner](https://git.marketally.com/gitcaddy/act_runner) - Enhanced runner with capabilities detection
|
||||
# GitCaddy MCP Server
|
||||
|
||||
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that enables AI assistants like Claude to interact directly with your GitCaddy instance.
|
||||
|
||||
## Features
|
||||
|
||||
- **Query Runners** - List runners, check status, view capabilities (OS, tools, disk space)
|
||||
- **Monitor Workflows** - List runs, get job details, view logs
|
||||
- **Manage Releases** - List releases, get assets, check download counts
|
||||
- **AI Learning** - Query error patterns, report solutions, help other AIs learn
|
||||
- **AI-Friendly** - Structured JSON responses designed for AI consumption
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Download
|
||||
|
||||
Download the latest binary from [Releases](https://git.marketally.com/gitcaddy/mcp-server/releases).
|
||||
|
||||
### 2. Configure Claude Code
|
||||
|
||||
Add to your Claude Code settings:
|
||||
|
||||
**Option A: Command line arguments**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitcaddy": {
|
||||
"command": "/path/to/gitcaddy-mcp-server",
|
||||
"args": ["--url", "https://git.marketally.com", "--token", "YOUR_API_TOKEN"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Option B: Environment variables**
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"gitcaddy": {
|
||||
"command": "/path/to/gitcaddy-mcp-server",
|
||||
"env": {
|
||||
"GITCADDY_URL": "https://git.marketally.com",
|
||||
"GITCADDY_TOKEN": "your-token-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Use It
|
||||
|
||||
Ask Claude things like:
|
||||
- "What runners are online?"
|
||||
- "Show me the latest workflow runs for gitcaddy/act_runner"
|
||||
- "Why did run #77 fail?"
|
||||
- "What assets are in the v0.3.6 release?"
|
||||
- "Are there any known solutions for NETSDK1147?"
|
||||
- "Diagnose why job 456 failed"
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Runner & Workflow Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `list_runners` | List all runners with status, capabilities, disk space |
|
||||
| `get_runner` | Get detailed runner info by ID |
|
||||
| `list_workflow_runs` | List workflow runs for a repository |
|
||||
| `get_workflow_run` | Get run details with all jobs |
|
||||
| `get_job_logs` | Get logs from a specific job |
|
||||
| `list_releases` | List releases for a repository |
|
||||
| `get_release` | Get release details with all assets |
|
||||
|
||||
### AI Learning Tools
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `get_error_patterns` | Query known CI/CD error patterns with diagnoses and solutions |
|
||||
| `report_error_solution` | Report a solution that fixed an error (helps other AIs learn) |
|
||||
| `report_solution_success` | Mark a solution as successful (improves ranking) |
|
||||
| `get_compatibility_matrix` | See what project types work on which runners |
|
||||
| `diagnose_job_failure` | Auto-analyze failed job logs and suggest solutions |
|
||||
|
||||
## AI Learning System
|
||||
|
||||
GitCaddy includes a collaborative AI learning system. When you encounter and fix CI/CD errors, you can report your solutions to help other AI assistants:
|
||||
|
||||
```
|
||||
AI encounters error -> get_error_patterns -> finds solution -> applies fix
|
||||
|
|
||||
v
|
||||
report_solution_success
|
||||
(improves ranking)
|
||||
|
||||
AI finds NEW solution -> report_error_solution -> stored in database
|
||||
|
|
||||
v
|
||||
Other AIs can now find it
|
||||
```
|
||||
|
||||
### Example: Diagnosing a Failed Build
|
||||
|
||||
```
|
||||
User: "Why did job 789 fail?"
|
||||
|
||||
Claude uses: diagnose_job_failure(owner="myorg", repo="myapp", job_id=789)
|
||||
|
||||
Response:
|
||||
{
|
||||
"extracted_errors": ["NETSDK1147", "XA5300"],
|
||||
"diagnoses": [
|
||||
{
|
||||
"pattern": "NETSDK1147",
|
||||
"diagnosis": "The .NET MAUI Android workload is not installed",
|
||||
"solution": "Install the workload: dotnet workload install maui-android",
|
||||
"success_rate": 94.5
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
git clone https://git.marketally.com/gitcaddy/mcp-server.git
|
||||
cd mcp-server
|
||||
go build -o gitcaddy-mcp-server .
|
||||
```
|
||||
|
||||
### Cross-compile for all platforms
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
GOOS=linux GOARCH=amd64 go build -o gitcaddy-mcp-server-linux-amd64 .
|
||||
|
||||
# macOS Intel
|
||||
GOOS=darwin GOARCH=amd64 go build -o gitcaddy-mcp-server-darwin-amd64 .
|
||||
|
||||
# macOS Apple Silicon
|
||||
GOOS=darwin GOARCH=arm64 go build -o gitcaddy-mcp-server-darwin-arm64 .
|
||||
|
||||
# Windows
|
||||
GOOS=windows GOARCH=amd64 go build -o gitcaddy-mcp-server-windows-amd64.exe .
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
+-------------+ stdio +------------------+ HTTP +-------------+
|
||||
| Claude Code | <------------> | gitcaddy-mcp | <-----------> | GitCaddy |
|
||||
| (AI Tool) | JSON-RPC | (This binary) | /api/v2/mcp | Server |
|
||||
+-------------+ +------------------+ +-------------+
|
||||
```
|
||||
|
||||
The MCP server:
|
||||
1. Receives JSON-RPC requests over stdio from Claude Code
|
||||
2. Forwards them to GitCaddy's `/api/v2/mcp` endpoint
|
||||
3. Returns responses back to Claude Code
|
||||
|
||||
## Configuration Options
|
||||
|
||||
| Flag | Env Variable | Description |
|
||||
|------|-------------|-------------|
|
||||
| `--url` | `GITCADDY_URL` | GitCaddy server URL (required) |
|
||||
| `--token` | `GITCADDY_TOKEN` | API token for authentication |
|
||||
| `--debug` | - | Enable debug logging to stderr |
|
||||
|
||||
**Note:** `GITEA_URL` and `GITEA_TOKEN` are also supported for backwards compatibility.
|
||||
|
||||
## Obtaining an API Token
|
||||
|
||||
1. Go to your GitCaddy instance -> Settings -> Applications
|
||||
2. Generate a new token with appropriate scopes
|
||||
3. Copy the token and use it in your configuration
|
||||
|
||||
## Requirements
|
||||
|
||||
- GitCaddy Server (Gitea 1.26+ with GitCaddy enhancements)
|
||||
- Go 1.21+ (for building from source)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See [LICENSE](LICENSE) file.
|
||||
|
||||
## Related Projects
|
||||
|
||||
- [GitCaddy Server](https://git.marketally.com/gitcaddy/gitea) - Enhanced Gitea fork with AI-friendly APIs
|
||||
- [GitCaddy Runner](https://git.marketally.com/gitcaddy/act_runner) - Enhanced runner with capabilities detection
|
||||
|
||||
312
main.go
312
main.go
@@ -1,153 +1,159 @@
|
||||
// Copyright 2026 MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Gitea MCP Server - Model Context Protocol server for Gitea Actions
|
||||
//
|
||||
// This standalone server implements the MCP protocol over stdio,
|
||||
// proxying requests to a Gitea instance's /api/v2/mcp endpoint.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// gitea-mcp-server --url https://git.example.com --token YOUR_API_TOKEN
|
||||
//
|
||||
// Configure in Claude Code's settings.json:
|
||||
//
|
||||
// {
|
||||
// "mcpServers": {
|
||||
// "gitea": {
|
||||
// "command": "gitea-mcp-server",
|
||||
// "args": ["--url", "https://git.example.com", "--token", "YOUR_TOKEN"]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
giteaURL string
|
||||
giteaToken string
|
||||
debug bool
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&giteaURL, "url", "", "Gitea server URL (e.g., https://git.example.com)")
|
||||
flag.StringVar(&giteaToken, "token", "", "Gitea API token")
|
||||
flag.BoolVar(&debug, "debug", false, "Enable debug logging to stderr")
|
||||
flag.Parse()
|
||||
|
||||
// Also check environment variables
|
||||
if giteaURL == "" {
|
||||
giteaURL = os.Getenv("GITEA_URL")
|
||||
}
|
||||
if giteaToken == "" {
|
||||
giteaToken = os.Getenv("GITEA_TOKEN")
|
||||
}
|
||||
|
||||
if giteaURL == "" {
|
||||
fmt.Fprintln(os.Stderr, "Error: --url or GITEA_URL is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
debugLog("Gitea MCP Server starting")
|
||||
debugLog("Connecting to: %s", giteaURL)
|
||||
|
||||
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
line, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
debugLog("EOF received, exiting")
|
||||
break
|
||||
}
|
||||
debugLog("Read error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
debugLog("Received: %s", string(line))
|
||||
|
||||
// Forward to Gitea's MCP endpoint
|
||||
response, err := forwardToGitea(line)
|
||||
if err != nil {
|
||||
debugLog("Forward error: %v", err)
|
||||
// Send error response
|
||||
errorResp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": nil,
|
||||
"error": map[string]interface{}{
|
||||
"code": -32603,
|
||||
"message": "Internal error",
|
||||
"data": err.Error(),
|
||||
},
|
||||
}
|
||||
writeResponse(errorResp)
|
||||
continue
|
||||
}
|
||||
|
||||
debugLog("Response: %s", string(response))
|
||||
|
||||
// Write response to stdout
|
||||
fmt.Println(string(response))
|
||||
}
|
||||
}
|
||||
|
||||
func forwardToGitea(request []byte) ([]byte, error) {
|
||||
mcpURL := giteaURL + "/api/v2/mcp"
|
||||
|
||||
req, err := http.NewRequest("POST", mcpURL, bytes.NewReader(request))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
if giteaToken != "" {
|
||||
req.Header.Set("Authorization", "token "+giteaToken)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("http request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func writeResponse(resp interface{}) {
|
||||
data, _ := json.Marshal(resp)
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
|
||||
func debugLog(format string, args ...interface{}) {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
// Copyright 2026 MarketAlly. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// GitCaddy MCP Server - Model Context Protocol server for GitCaddy/Gitea Actions
|
||||
//
|
||||
// This standalone server implements the MCP protocol over stdio,
|
||||
// proxying requests to a GitCaddy instance's /api/v2/mcp endpoint.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// gitcaddy-mcp-server --url https://git.example.com --token YOUR_API_TOKEN
|
||||
//
|
||||
// Configure in Claude Code's settings.json:
|
||||
//
|
||||
// {
|
||||
// "mcpServers": {
|
||||
// "gitcaddy": {
|
||||
// "command": "gitcaddy-mcp-server",
|
||||
// "args": ["--url", "https://git.example.com", "--token", "YOUR_TOKEN"]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
giteaURL string
|
||||
giteaToken string
|
||||
debug bool
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&giteaURL, "url", "", "GitCaddy server URL (e.g., https://git.example.com)")
|
||||
flag.StringVar(&giteaToken, "token", "", "GitCaddy API token")
|
||||
flag.BoolVar(&debug, "debug", false, "Enable debug logging to stderr")
|
||||
flag.Parse()
|
||||
|
||||
// Check environment variables (GITCADDY_* preferred, GITEA_* for backwards compat)
|
||||
if giteaURL == "" {
|
||||
giteaURL = os.Getenv("GITCADDY_URL")
|
||||
}
|
||||
if giteaURL == "" {
|
||||
giteaURL = os.Getenv("GITEA_URL")
|
||||
}
|
||||
if giteaToken == "" {
|
||||
giteaToken = os.Getenv("GITCADDY_TOKEN")
|
||||
}
|
||||
if giteaToken == "" {
|
||||
giteaToken = os.Getenv("GITEA_TOKEN")
|
||||
}
|
||||
|
||||
if giteaURL == "" {
|
||||
fmt.Fprintln(os.Stderr, "Error: --url or GITCADDY_URL is required")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
debugLog("GitCaddy MCP Server starting")
|
||||
debugLog("Connecting to: %s", giteaURL)
|
||||
|
||||
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
line, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
debugLog("EOF received, exiting")
|
||||
break
|
||||
}
|
||||
debugLog("Read error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
debugLog("Received: %s", string(line))
|
||||
|
||||
// Forward to Gitea's MCP endpoint
|
||||
response, err := forwardToGitea(line)
|
||||
if err != nil {
|
||||
debugLog("Forward error: %v", err)
|
||||
// Send error response
|
||||
errorResp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": nil,
|
||||
"error": map[string]interface{}{
|
||||
"code": -32603,
|
||||
"message": "Internal error",
|
||||
"data": err.Error(),
|
||||
},
|
||||
}
|
||||
writeResponse(errorResp)
|
||||
continue
|
||||
}
|
||||
|
||||
debugLog("Response: %s", string(response))
|
||||
|
||||
// Write response to stdout
|
||||
fmt.Println(string(response))
|
||||
}
|
||||
}
|
||||
|
||||
func forwardToGitea(request []byte) ([]byte, error) {
|
||||
mcpURL := giteaURL + "/api/v2/mcp"
|
||||
|
||||
req, err := http.NewRequest("POST", mcpURL, bytes.NewReader(request))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create request: %w", err)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
if giteaToken != "" {
|
||||
req.Header.Set("Authorization", "token "+giteaToken)
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("http request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read response: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("http status %d: %s", resp.StatusCode, string(body))
|
||||
}
|
||||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func writeResponse(resp interface{}) {
|
||||
data, _ := json.Marshal(resp)
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
|
||||
func debugLog(format string, args ...interface{}) {
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "[DEBUG] "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user