File size: 3,952 Bytes
f18435c
 
 
d520cc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f18435c
 
 
 
 
d520cc3
 
f18435c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d520cc3
f18435c
d520cc3
 
 
 
 
 
 
 
 
 
 
 
f18435c
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# explain_error.py

from extract_error_features import extract_error_features
from retrieve_docs import retrieve_docs

SYSTEM_PROMPT = """
You are a Jenkins CI/CD expert.

Explain the Jenkins error using ONLY the provided documentation context.
If the documentation does not clearly explain the error, say so explicitly.

Output format:

Error Summary:
<short explanation>

Likely Causes:
- cause 1
- cause 2

Relevant Documentation:
- link or source file
"""

def explain_error(log_text: str):
    features = extract_error_features(log_text)
    category = features["category"]

    retrieved = retrieve_docs(category)

    explanation = {
        "error_category": category,
        "summary": "",
        "likely_causes": [],
        "references": []
    }

    # Heuristic explanation (v1, deterministic)
    if category == "groovy_syntax_error":
        explanation["summary"] = (
            "The pipeline failed due to a Groovy syntax error, "
            "most likely caused by an invalid or incomplete Jenkinsfile."
        )
        explanation["likely_causes"] = [
            "Missing or mismatched braces in the Jenkinsfile",
            "Invalid declarative pipeline structure"
        ]

    elif category == "missing_agent":
        explanation["summary"] = (
            "The pipeline attempted to execute a step that requires a node, "
            "but no agent was allocated."
        )
        explanation["likely_causes"] = [
            "Using 'agent none' without defining a stage-level agent",
            "Executing node-dependent steps without a workspace"
        ]

    elif category == "no_node_available":
        explanation["summary"] = (
            "The pipeline could not be scheduled because no Jenkins node "
            "matched the requested label."
        )
        explanation["likely_causes"] = [
            "The specified node label does not exist",
            "All matching nodes are offline or busy"
        ]

    elif category == "missing_plugin":
        explanation["summary"] = (
            "The pipeline referenced a step that is not available, "
            "indicating a missing or uninstalled plugin."
        )
        explanation["likely_causes"] = [
            "Required plugin is not installed",
            "Incorrect step name in the Jenkinsfile"
        ]

    elif category == "missing_credentials":
        explanation["summary"] = (
            "The pipeline referenced credentials that do not exist in Jenkins."
        )
        explanation["likely_causes"] = [
            "Credentials ID is incorrect or misspelled",
            "Credentials were not configured in Jenkins"
        ]

    elif category == "file_not_found":
        explanation["summary"] = (
            "The pipeline attempted to access a file that does not exist "
            "in the workspace."
        )
        explanation["likely_causes"] = [
            "File path is incorrect",
            "File was not generated or checked out"
        ]

    elif category == "git_authentication_error":
        explanation["summary"] = (
            "Jenkins failed to authenticate with the Git repository during checkout."
        )
        explanation["likely_causes"] = [
            "Invalid or missing Git credentials",
            "Repository requires token-based authentication"
        ]

    else:
        explanation["summary"] = (
            "The error could not be confidently explained using the available documentation."
        )

    for r in retrieved:
        explanation["references"].append(
            f"{r['meta']['source_file']} ({r['meta']['source']})"
        )
    if not retrieved:
        explanation["summary"] = (
            "No relevant Jenkins documentation was found for this error. "
            "The error may be plugin-specific or outside the current scope."
        )
        explanation["likely_causes"] = []
        explanation["references"] = []

    return explanation