Skip to content

Commit 1100b37

Browse files
cfsmp3claude
andcommitted
fix: Improve error messages for missing build artifacts
When a test fails due to missing build artifacts, users previously saw only a generic "An error occurred" message. This made it difficult to understand what went wrong. Changes: - Add `error_message` property to Test model to expose the last error - Update test detail template to show error message prominently in an alert box instead of hiding it in the progress table - Add `_diagnose_missing_artifact()` helper that checks GitHub workflow status and provides specific error messages: - "Build still in progress" - when the GitHub Actions build hasn't completed yet (common for Windows builds which take ~40 minutes) - "Build failed" - when the workflow failed - "Artifact not found" - when build succeeded but artifact missing (possibly expired) - "No workflow run found" - when the workflow hasn't started This helps users understand why their test failed and what action to take (e.g., wait for build to complete, check GitHub Actions logs). Fixes the issue where test 7139 showed a cryptic error because the Windows build was still in progress when the test tried to fetch the artifact. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 53b3d7f commit 1100b37

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

mod_ci/controllers.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,57 @@ def mark_test_failed(db, test, repository, message: str) -> None:
304304
log.error(f"Failed to mark test {test.id} as failed: {e}")
305305

306306

307+
def _diagnose_missing_artifact(repository, commit_sha: str, expected_workflow: str, log) -> str:
308+
"""
309+
Diagnose why an artifact was not found for a commit.
310+
311+
Checks the workflow run status to provide a more helpful error message.
312+
313+
:param repository: GitHub repository object
314+
:param commit_sha: The commit SHA to check
315+
:param expected_workflow: The expected workflow name (e.g., "Build CCExtractor on Windows")
316+
:param log: Logger instance
317+
:return: A descriptive error message
318+
"""
319+
from collections import defaultdict
320+
321+
try:
322+
# Build workflow name lookup
323+
workflow = defaultdict(lambda: None)
324+
for active_workflow in repository.get_workflows():
325+
workflow[active_workflow.id] = active_workflow.name
326+
327+
# Check workflow runs for this commit
328+
workflow_found = False
329+
for workflow_run in repository.get_workflow_runs(head_sha=commit_sha):
330+
workflow_run_name = workflow[workflow_run.workflow_id]
331+
if workflow_run_name != expected_workflow:
332+
continue
333+
334+
workflow_found = True
335+
if workflow_run.status != "completed":
336+
return (f"Build still in progress: '{expected_workflow}' is {workflow_run.status}. "
337+
f"Please wait for the build to complete and retry.")
338+
elif workflow_run.conclusion != "success":
339+
return (f"Build failed: '{expected_workflow}' finished with conclusion '{workflow_run.conclusion}'. "
340+
f"Check the GitHub Actions logs for details.")
341+
else:
342+
# Build succeeded but artifact not found - may have expired
343+
return (f"Artifact not found: '{expected_workflow}' completed successfully, "
344+
f"but no artifact was found. The artifact may have expired (GitHub deletes "
345+
f"artifacts after a retention period) or was not uploaded properly.")
346+
347+
if not workflow_found:
348+
return (f"No workflow run found: '{expected_workflow}' has not run for commit {commit_sha[:7]}. "
349+
f"This may indicate the workflow was not triggered or is queued.")
350+
351+
except Exception as e:
352+
log.warning(f"Failed to diagnose missing artifact: {e}")
353+
return f"No build artifact found for this commit (diagnostic check failed: {e})"
354+
355+
return "No build artifact found for this commit"
356+
357+
307358
def start_test(compute, app, db, repository: Repository.Repository, test, bot_token) -> None:
308359
"""
309360
Start a VM instance and run the tests.
@@ -439,8 +490,10 @@ def start_test(compute, app, db, repository: Repository.Repository, test, bot_to
439490
artifacts = repository.get_artifacts()
440491
if test.platform == TestPlatform.linux:
441492
artifact_name = Artifact_names.linux
493+
workflow_name = Workflow_builds.LINUX
442494
else:
443495
artifact_name = Artifact_names.windows
496+
workflow_name = Workflow_builds.WINDOWS
444497
for index, artifact in enumerate(artifacts):
445498
if artifact.name == artifact_name and artifact.workflow_run.head_sha == test.commit:
446499
artifact_url = artifact.archive_download_url
@@ -474,8 +527,10 @@ def start_test(compute, app, db, repository: Repository.Repository, test, bot_to
474527
break
475528

476529
if not artifact_saved:
477-
log.critical("Could not find an artifact for this commit")
478-
mark_test_failed(db, test, repository, "No build artifact found for this commit")
530+
# Try to diagnose why no artifact was found by checking workflow run status
531+
error_detail = _diagnose_missing_artifact(repository, test.commit, workflow_name, log)
532+
log.critical(f"Could not find artifact for commit {test.commit}: {error_detail}")
533+
mark_test_failed(db, test, repository, error_detail)
479534
return
480535

481536
zone = config.get('ZONE', '')

mod_test/models.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ def failed(self):
183183
return self.progress[-1].status == TestStatus.canceled
184184
return False
185185

186+
@property
187+
def error_message(self):
188+
"""
189+
Get the error message if the test failed.
190+
191+
:return: The error message from the last progress entry, or None if not failed
192+
:rtype: str or None
193+
"""
194+
if self.failed and len(self.progress) > 0:
195+
return self.progress[-1].message
196+
return None
197+
186198
@property
187199
def github_link(self):
188200
"""

templates/test/by_id.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@ <h1>Test progress for {{ title }}</h1>
8383
{% if test.finished %}
8484
{% if test.failed %}
8585
<h2>An error occurred</h2>
86-
<p>Something went wrong while the tests where running. You should be able to see in the bar above during which stage it went wrong exactly.</p>
86+
{% if test.error_message %}
87+
<div class="callout alert">
88+
<strong>Error:</strong> {{ test.error_message }}
89+
</div>
90+
{% endif %}
91+
<p>Something went wrong while the tests were running. You can see the progress timeline above for more details.</p>
8792
<p>If you have build errors, you can access the above log file with build errors.</p>
8893
{% else %}
8994
<h2>Test results</h2>

0 commit comments

Comments
 (0)