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
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:
73
models/ai/seed.go
Normal file
73
models/ai/seed.go
Normal 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
|
||||
})
|
||||
}
|
||||
94
options/seed/error_patterns.json
Normal file
94
options/seed/error_patterns.json
Normal 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."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user