2
0

feat(ai): Add auto-seed for error patterns on fresh deploy
Some checks failed
Build and Release / Lint (push) Failing after 5m0s
Build and Release / Build Binaries (amd64, darwin) (push) Has been skipped
Build and Release / Unit Tests (push) Successful in 4m54s
Build and Release / Create Release (push) Has been skipped
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 4m35s
Build and Release / Build Binaries (amd64, linux) (push) Has been skipped
Build and Release / Build Binaries (amd64, windows) (push) Has been skipped
Build and Release / Build Binaries (arm64, darwin) (push) Has been skipped
Build and Release / Build Binaries (arm64, linux) (push) Has been skipped

- Add options/seed/error_patterns.json with default upload error patterns
- Add models/ai/seed.go with SeedErrorPatternsIfEmpty function
- Call seed on startup after models.Init if error_pattern table is empty
- Seeds 10 common error patterns for uploads, .NET, etc.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
GitCaddy
2026-01-14 07:22:04 +00:00
parent 4dda9056a9
commit ef12907faf
3 changed files with 169 additions and 0 deletions

73
models/ai/seed.go Normal file
View File

@@ -0,0 +1,73 @@
// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT
package ai
import (
"context"
"encoding/json"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/options"
)
// SeedData represents the structure of the seed JSON file
type SeedData struct {
Patterns []struct {
Pattern string `json:"pattern"`
RunnerType string `json:"runner_type"`
ProjectType string `json:"project_type"`
Framework string `json:"framework"`
ErrorMessage string `json:"error_message"`
Diagnosis string `json:"diagnosis"`
Solution string `json:"solution"`
} `json:"patterns"`
}
// SeedErrorPatternsIfEmpty seeds error patterns from the seed file if the table is empty
func SeedErrorPatternsIfEmpty(ctx context.Context) error {
count, err := db.GetEngine(ctx).Count(&ErrorPattern{})
if err != nil {
return err
}
if count > 0 {
log.Debug("Error patterns table already has %d entries, skipping seed", count)
return nil
}
log.Info("Seeding error patterns from seed file...")
// Load seed data from embedded options
data, err := options.AssetFS().ReadFile("seed/error_patterns.json")
if err != nil {
log.Warn("Could not read error patterns seed file: %v", err)
return nil // Not an error, just no seed file
}
var seedData SeedData
if err := json.Unmarshal(data, &seedData); err != nil {
log.Error("Failed to parse error patterns seed file: %v", err)
return err
}
return db.WithTx(ctx, func(ctx context.Context) error {
for _, p := range seedData.Patterns {
ep := &ErrorPattern{
Pattern: p.Pattern,
RunnerType: p.RunnerType,
ProjectType: p.ProjectType,
Framework: p.Framework,
ErrorMessage: p.ErrorMessage,
Diagnosis: p.Diagnosis,
Solution: p.Solution,
}
if err := db.Insert(ctx, ep); err != nil {
return err
}
}
log.Info("Seeded %d error patterns", len(seedData.Patterns))
return nil
})
}

View File

@@ -0,0 +1,94 @@
{
"patterns": [
{
"pattern": "curl: (28) Connection timed out",
"runner_type": "linux",
"project_type": "release-upload",
"framework": "curl",
"error_message": "curl: (28) Connection timed out after X milliseconds",
"diagnosis": "The upload connection timed out. This typically occurs with large files over unstable networks or when server timeouts are too short.",
"solution": "Use HTTP/1.1 with keepalive and extended timeouts: curl --http1.1 --keepalive-time 60 --connect-timeout 120 --max-time 3600 --retry 5 --retry-delay 10"
},
{
"pattern": "curl: (56) Recv failure: Connection reset by peer",
"runner_type": "linux",
"project_type": "release-upload",
"framework": "curl",
"error_message": "curl: (56) Recv failure: Connection reset by peer",
"diagnosis": "The connection was reset during upload. This often happens with HTTP/2 multiplexing issues or when proxies/load balancers terminate idle connections.",
"solution": "Force HTTP/1.1 to avoid multiplexing issues: curl --http1.1 --retry 5 --retry-all-errors -X POST -F attachment=@file"
},
{
"pattern": "file_too_large",
"runner_type": "",
"project_type": "release-upload",
"framework": "gitcaddy-api",
"error_message": "File exceeds maximum size",
"diagnosis": "The uploaded file exceeds the server maximum attachment size limit.",
"solution": "Check max size with GET /api/v2/upload/instructions. Split large files or request server config increase. Default limit is typically 500MB."
},
{
"pattern": "curl: (35) SSL connect error",
"runner_type": "linux",
"project_type": "release-upload",
"framework": "curl",
"error_message": "curl: (35) SSL connect error or OpenSSL SSL_connect error",
"diagnosis": "SSL/TLS handshake failed. May be caused by certificate issues, protocol mismatch, or network interference.",
"solution": "Try with explicit TLS version: curl --tlsv1.2 or check certificate validity. For self-signed certs in testing, use -k flag."
},
{
"pattern": "curl: (6) Could not resolve host",
"runner_type": "linux",
"project_type": "release-upload",
"framework": "curl",
"error_message": "curl: (6) Could not resolve host: git.example.com",
"diagnosis": "DNS resolution failed for the upload server hostname.",
"solution": "Pre-warm DNS before upload: curl -s -o /dev/null -I https://server/api/healthz; then retry upload. Check /etc/resolv.conf and network connectivity."
},
{
"pattern": "upload_failed",
"runner_type": "",
"project_type": "release-upload",
"framework": "gitcaddy-api",
"error_message": "upload_failed: unexpected EOF or connection closed",
"diagnosis": "Upload was interrupted before completion. Often caused by network instability or timeout during large file transfers.",
"solution": "Use gitcaddy-upload helper with automatic retry: gitcaddy-upload -url URL -token TOKEN -file FILE -retries 5. Or use curl with --retry 5 --retry-all-errors flags."
},
{
"pattern": "HTTP 413 Request Entity Too Large",
"runner_type": "",
"project_type": "release-upload",
"framework": "http",
"error_message": "HTTP 413 Request Entity Too Large or Payload Too Large",
"diagnosis": "The request body exceeds the server or reverse proxy limit. Nginx/Caddy may have lower limits than the application.",
"solution": "Check proxy config: nginx client_max_body_size, Caddy request_body max_size. Ensure all layers allow the file size."
},
{
"pattern": "NETSDK1147",
"runner_type": "macos",
"project_type": "dotnet-maui",
"framework": "net9.0-android",
"error_message": "NETSDK1147: To build this project, the following workloads must be installed: maui-android",
"diagnosis": "The .NET MAUI Android workload is not installed on the build machine.",
"solution": "Install the workload: dotnet workload install maui-android. For CI, add this step before build."
},
{
"pattern": "XA5300",
"runner_type": "macos",
"project_type": "dotnet-maui",
"framework": "net9.0-android",
"error_message": "XA5300: The Android SDK directory could not be found",
"diagnosis": "Android SDK is not installed or ANDROID_HOME environment variable is not set.",
"solution": "Set ANDROID_HOME to the SDK path. On macOS: export ANDROID_HOME=$HOME/Library/Android/sdk"
},
{
"pattern": "MSB4019",
"runner_type": "",
"project_type": "dotnet",
"framework": "",
"error_message": "MSB4019: The imported project was not found",
"diagnosis": "A required MSBuild targets file is missing, usually due to missing SDK or workload.",
"solution": "Install the required workload or SDK. Run: dotnet workload list to see installed workloads."
}
]
}

View File

@@ -10,6 +10,7 @@ import (
"runtime"
"code.gitea.io/gitea/models"
ai_model "code.gitea.io/gitea/models/ai"
authmodel "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/eventsource"
@@ -151,6 +152,7 @@ func InitWebInstalled(ctx context.Context) {
mustInit(release_service.Init)
mustInitCtx(ctx, models.Init)
mustInitCtx(ctx, ai_model.SeedErrorPatternsIfEmpty)
mustInitCtx(ctx, authmodel.Init)
mustInitCtx(ctx, repo_service.Init)