mirror of
https://github.com/esphome/esphome.git
synced 2026-01-09 11:40:50 -07:00
[ci] Allow memory impact target branch build to fail without blocking CI (#12381)
This commit is contained in:
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -959,13 +959,13 @@ jobs:
|
|||||||
- memory-impact-comment
|
- memory-impact-comment
|
||||||
if: always()
|
if: always()
|
||||||
steps:
|
steps:
|
||||||
- name: Success
|
- name: Check job results
|
||||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
|
||||||
run: exit 0
|
|
||||||
- name: Failure
|
|
||||||
if: ${{ contains(needs.*.result, 'failure') }}
|
|
||||||
env:
|
env:
|
||||||
JSON_DOC: ${{ toJSON(needs) }}
|
NEEDS_JSON: ${{ toJSON(needs) }}
|
||||||
run: |
|
run: |
|
||||||
echo $JSON_DOC | jq
|
# memory-impact-target-branch is allowed to fail without blocking CI.
|
||||||
exit 1
|
# This job builds the target branch (dev/beta/release) which may fail because:
|
||||||
|
# 1. The target branch has a build issue independent of this PR
|
||||||
|
# 2. This PR fixes a build issue on the target branch
|
||||||
|
# In either case, we only care that the PR branch builds successfully.
|
||||||
|
echo "$NEEDS_JSON" | jq -e 'del(.["memory-impact-target-branch"]) | all(.result != "failure")'
|
||||||
|
|||||||
@@ -215,6 +215,20 @@ def prepare_symbol_changes_data(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def format_components_str(components: list[str]) -> str:
|
||||||
|
"""Format a list of components for display.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
components: List of component names
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Formatted string with backtick-quoted component names
|
||||||
|
"""
|
||||||
|
if len(components) == 1:
|
||||||
|
return f"`{components[0]}`"
|
||||||
|
return ", ".join(f"`{c}`" for c in sorted(components))
|
||||||
|
|
||||||
|
|
||||||
def prepare_component_breakdown_data(
|
def prepare_component_breakdown_data(
|
||||||
target_analysis: dict | None, pr_analysis: dict | None
|
target_analysis: dict | None, pr_analysis: dict | None
|
||||||
) -> list[tuple[str, int, int, int]] | None:
|
) -> list[tuple[str, int, int, int]] | None:
|
||||||
@@ -316,11 +330,10 @@ def create_comment_body(
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Format components list
|
# Format components list
|
||||||
|
context["components_str"] = format_components_str(components)
|
||||||
if len(components) == 1:
|
if len(components) == 1:
|
||||||
context["components_str"] = f"`{components[0]}`"
|
|
||||||
context["config_note"] = "a representative test configuration"
|
context["config_note"] = "a representative test configuration"
|
||||||
else:
|
else:
|
||||||
context["components_str"] = ", ".join(f"`{c}`" for c in sorted(components))
|
|
||||||
context["config_note"] = (
|
context["config_note"] = (
|
||||||
f"a merged configuration with {len(components)} components"
|
f"a merged configuration with {len(components)} components"
|
||||||
)
|
)
|
||||||
@@ -502,6 +515,43 @@ def post_or_update_comment(pr_number: str, comment_body: str) -> None:
|
|||||||
print("Comment posted/updated successfully", file=sys.stderr)
|
print("Comment posted/updated successfully", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def create_target_unavailable_comment(
|
||||||
|
pr_data: dict,
|
||||||
|
) -> str:
|
||||||
|
"""Create a comment body when target branch data is unavailable.
|
||||||
|
|
||||||
|
This happens when the target branch (dev/beta/release) fails to build.
|
||||||
|
This can occur because:
|
||||||
|
1. The target branch has a build issue independent of this PR
|
||||||
|
2. This PR fixes a build issue on the target branch
|
||||||
|
In either case, we only care that the PR branch builds successfully.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
pr_data: Dictionary with PR branch analysis results
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Formatted comment body
|
||||||
|
"""
|
||||||
|
components = pr_data.get("components", [])
|
||||||
|
platform = pr_data.get("platform", "unknown")
|
||||||
|
pr_ram = pr_data.get("ram_bytes", 0)
|
||||||
|
pr_flash = pr_data.get("flash_bytes", 0)
|
||||||
|
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(TEMPLATE_DIR),
|
||||||
|
trim_blocks=True,
|
||||||
|
lstrip_blocks=True,
|
||||||
|
)
|
||||||
|
template = env.get_template("ci_memory_impact_target_unavailable.j2")
|
||||||
|
return template.render(
|
||||||
|
comment_marker=COMMENT_MARKER,
|
||||||
|
components_str=format_components_str(components),
|
||||||
|
platform=platform,
|
||||||
|
pr_ram=format_bytes(pr_ram),
|
||||||
|
pr_flash=format_bytes(pr_flash),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
"""Main entry point."""
|
"""Main entry point."""
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@@ -523,15 +573,25 @@ def main() -> int:
|
|||||||
|
|
||||||
# Load analysis JSON files (all data comes from JSON for security)
|
# Load analysis JSON files (all data comes from JSON for security)
|
||||||
target_data: dict | None = load_analysis_json(args.target_json)
|
target_data: dict | None = load_analysis_json(args.target_json)
|
||||||
if not target_data:
|
|
||||||
print("Error: Failed to load target analysis JSON", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
pr_data: dict | None = load_analysis_json(args.pr_json)
|
pr_data: dict | None = load_analysis_json(args.pr_json)
|
||||||
|
|
||||||
|
# PR data is required - if the PR branch can't build, that's a real error
|
||||||
if not pr_data:
|
if not pr_data:
|
||||||
print("Error: Failed to load PR analysis JSON", file=sys.stderr)
|
print("Error: Failed to load PR analysis JSON", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Target data is optional - target branch (dev) may fail to build because:
|
||||||
|
# 1. The target branch has a build issue independent of this PR
|
||||||
|
# 2. This PR fixes a build issue on the target branch
|
||||||
|
if not target_data:
|
||||||
|
print(
|
||||||
|
"Warning: Target branch analysis unavailable, posting limited comment",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
comment_body = create_target_unavailable_comment(pr_data)
|
||||||
|
post_or_update_comment(args.pr_number, comment_body)
|
||||||
|
return 0
|
||||||
|
|
||||||
# Extract detailed analysis if available
|
# Extract detailed analysis if available
|
||||||
target_analysis: dict | None = None
|
target_analysis: dict | None = None
|
||||||
pr_analysis: dict | None = None
|
pr_analysis: dict | None = None
|
||||||
|
|||||||
19
script/templates/ci_memory_impact_target_unavailable.j2
Normal file
19
script/templates/ci_memory_impact_target_unavailable.j2
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{{ comment_marker }}
|
||||||
|
## Memory Impact Analysis
|
||||||
|
|
||||||
|
**Components:** {{ components_str }}
|
||||||
|
**Platform:** `{{ platform }}`
|
||||||
|
|
||||||
|
| Metric | This PR |
|
||||||
|
|--------|---------|
|
||||||
|
| **RAM** | {{ pr_ram }} |
|
||||||
|
| **Flash** | {{ pr_flash }} |
|
||||||
|
|
||||||
|
> ⚠️ **Target branch comparison unavailable** - The target branch failed to build.
|
||||||
|
> This can happen when the target branch has a build issue, or when this PR fixes a build issue on the target branch.
|
||||||
|
> The PR branch compiled successfully with the memory usage shown above.
|
||||||
|
|
||||||
|
---
|
||||||
|
> **Note:** This analysis measures **static RAM and Flash usage** only (compile-time allocation).
|
||||||
|
|
||||||
|
*This analysis runs automatically when components change.*
|
||||||
Reference in New Issue
Block a user