Skip to content

Commit 7667348

Browse files
author
Shikha Jha
committed
incorporate design review feedback
1 parent 5ef568c commit 7667348

4 files changed

Lines changed: 797 additions & 435 deletions

File tree

src/azure-cli/azure/cli/command_modules/appservice/_deployment_context_engine.py

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,46 @@
88
99
Instead of raising a bare "Status Code: 504" error, this module builds a structured
1010
diagnostic context block that includes the error code, deployment stage, runtime info,
11-
common causes, suggested fixes, and a ready-to-use Copilot prompt.
11+
suggested fixes, and a ready-to-use Copilot prompt.
1212
"""
1313

14-
import yaml
14+
import re
15+
1516
from knack.log import get_logger
1617
from knack.util import CLIError
1718

1819
from ._deployment_failure_patterns import match_failure_pattern
1920

2021
logger = get_logger(__name__)
2122

23+
# Patterns that reliably indicate an HTTP status code in CLI error messages.
24+
# Ordered from most specific to least specific; first match wins.
25+
_STATUS_CODE_PATTERNS = [
26+
re.compile(r'Status\s*Code[:\s]+(\d{3})', re.IGNORECASE), # "Status Code: 400"
27+
re.compile(r'\((([45]\d{2}))\)'), # "Bad Request(400)"
28+
re.compile(r'HTTP\s+(\d{3})', re.IGNORECASE), # "HTTP 504"
29+
re.compile(r'\b([45]\d{2})\s+(?:Bad|Unauthorized|Forbidden|Not\s+Found|Conflict|Too\s+Many|Internal|Gateway|Service)', re.IGNORECASE), # "400 Bad Request"
30+
]
2231

23-
def _safe_yaml_dump(data):
24-
"""Dump dict to YAML string, falling back to repr on error."""
25-
try:
26-
return yaml.dump(data, default_flow_style=False, sort_keys=False, allow_unicode=True).rstrip()
27-
except Exception: # pylint: disable=broad-except
28-
return repr(data)
32+
33+
def extract_status_code_from_message(message):
34+
"""Extract an HTTP status code (4xx/5xx) from a CLI error message string.
35+
36+
Uses targeted patterns ("Status Code: 400", "Bad Request(400)", "HTTP 504",
37+
"400 Bad Request") rather than blindly matching any 3-digit number, to avoid
38+
false positives from port numbers, exit codes, or counts.
39+
40+
Returns the integer status code, or None if no recognisable code is found.
41+
"""
42+
if not message:
43+
return None
44+
for pattern in _STATUS_CODE_PATTERNS:
45+
m = pattern.search(message)
46+
if m:
47+
code = int(m.group(1))
48+
if 400 <= code <= 599:
49+
return code
50+
return None
2951

3052

3153
def _get_app_runtime(cmd, resource_group_name, webapp_name, slot=None):
@@ -180,12 +202,10 @@ def build_enriched_error_context(params=None, *, cmd=None, resource_group_name=N
180202
params, src_url=_src_url, artifact_type=_artifact
181203
)
182204

183-
# Causes and fixes
205+
# Suggested fixes
184206
if pattern:
185-
context["commonCauses"] = pattern["commonCauses"]
186207
context["suggestedFixes"] = pattern["suggestedFixes"]
187208
else:
188-
context["commonCauses"] = ["Unrecognised failure — see error details below"]
189209
context["suggestedFixes"] = [
190210
"Check deployment logs: 'az webapp log deployment show -n {} -g {}'".format(
191211
_name or '<app>', _rg or '<rg>'),
@@ -227,22 +247,15 @@ def format_enriched_error_message(context):
227247
"""
228248
Format the structured context dict into a human-readable error message.
229249
230-
The output includes the YAML context block and a ready-to-use Copilot prompt.
250+
The output is a single formatted block with diagnostics and a Copilot prompt.
231251
"""
232252
lines = []
233253
lines.append("")
234254
lines.append("=" * 72)
235-
lines.append("DEPLOYMENT FAILED Context-Enriched Diagnostics")
255+
lines.append("DEPLOYMENT FAILED: Context-Enriched Diagnostics")
236256
lines.append("=" * 72)
237257
lines.append("")
238258

239-
# YAML context block
240-
lines.append("--- COPILOT CONTEXT ---")
241-
lines.append(_safe_yaml_dump(context))
242-
lines.append("--- END CONTEXT ---")
243-
lines.append("")
244-
245-
# Human-readable summary
246259
lines.append(f"Error Code : {context.get('errorCode', 'Unknown')}")
247260
lines.append(f"Stage : {context.get('stage', 'Unknown')}")
248261
lines.append(f"Runtime : {context.get('runtime', 'Unknown')}")
@@ -251,11 +264,8 @@ def format_enriched_error_message(context):
251264
lines.append(f"Plan SKU : {context.get('planSku', 'Unknown')}")
252265
lines.append("")
253266

254-
causes = context.get("commonCauses", [])
255-
if causes:
256-
lines.append("Common Causes:")
257-
for c in causes:
258-
lines.append(f" - {c}")
267+
if context.get("rawError"):
268+
lines.append(f"Raw Error : {context['rawError']}")
259269
lines.append("")
260270

261271
fixes = context.get("suggestedFixes", [])
@@ -265,17 +275,12 @@ def format_enriched_error_message(context):
265275
lines.append(f" - {f}")
266276
lines.append("")
267277

268-
if context.get("rawError"):
269-
lines.append(f"Raw Error : {context['rawError']}")
270-
lines.append("")
271-
272278
# Copilot prompt
273279
lines.append("-" * 72)
274280
lines.append("Ask Copilot:")
275-
lines.append(' Copy-paste the COPILOT CONTEXT block above into GitHub Copilot Chat,')
276-
lines.append(' or run:')
277-
lines.append(' gh copilot explain "Paste the COPILOT CONTEXT above and explain')
278-
lines.append(' why this deployment failed and what I should do"')
281+
lines.append(" Paste the error above into GitHub Copilot Chat, or run:")
282+
lines.append(' gh copilot explain "why did my deployment fail with')
283+
lines.append(f' {context.get("errorCode", "this error")} and what should I do"')
279284
lines.append("-" * 72)
280285

281286
return "\n".join(lines)

0 commit comments

Comments
 (0)