mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[ci] Fix memory impact analysis failing on fork PRs (#11380)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										108
									
								
								.github/workflows/ci-memory-impact-comment.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								.github/workflows/ci-memory-impact-comment.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| --- | ||||
| name: Memory Impact Comment (Forks) | ||||
|  | ||||
| on: | ||||
|   workflow_run: | ||||
|     workflows: ["CI"] | ||||
|     types: [completed] | ||||
|  | ||||
| permissions: | ||||
|   contents: read | ||||
|   pull-requests: write | ||||
|   actions: read | ||||
|  | ||||
| jobs: | ||||
|   memory-impact-comment: | ||||
|     name: Post memory impact comment (fork PRs only) | ||||
|     runs-on: ubuntu-24.04 | ||||
|     # Only run for PRs from forks that had successful CI runs | ||||
|     if: > | ||||
|       github.event.workflow_run.event == 'pull_request' && | ||||
|       github.event.workflow_run.conclusion == 'success' && | ||||
|       github.event.workflow_run.head_repository.full_name != github.repository | ||||
|     env: | ||||
|       GH_TOKEN: ${{ github.token }} | ||||
|     steps: | ||||
|       - name: Get PR details | ||||
|         id: pr | ||||
|         run: | | ||||
|           # Get PR details by searching for PR with matching head SHA | ||||
|           # The workflow_run.pull_requests field is often empty for forks | ||||
|           head_sha="${{ github.event.workflow_run.head_sha }}" | ||||
|           pr_data=$(gh api "/repos/${{ github.repository }}/commits/$head_sha/pulls" \ | ||||
|             --jq '.[0] | {number: .number, base_ref: .base.ref}') | ||||
|           if [ -z "$pr_data" ] || [ "$pr_data" == "null" ]; then | ||||
|             echo "No PR found for SHA $head_sha, skipping" | ||||
|             echo "skip=true" >> $GITHUB_OUTPUT | ||||
|             exit 0 | ||||
|           fi | ||||
|  | ||||
|           pr_number=$(echo "$pr_data" | jq -r '.number') | ||||
|           base_ref=$(echo "$pr_data" | jq -r '.base_ref') | ||||
|  | ||||
|           echo "pr_number=$pr_number" >> $GITHUB_OUTPUT | ||||
|           echo "base_ref=$base_ref" >> $GITHUB_OUTPUT | ||||
|           echo "Found PR #$pr_number targeting base branch: $base_ref" | ||||
|  | ||||
|       - name: Check out code from base repository | ||||
|         if: steps.pr.outputs.skip != 'true' | ||||
|         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||||
|         with: | ||||
|           # Always check out from the base repository (esphome/esphome), never from forks | ||||
|           # Use the PR's target branch to ensure we run trusted code from the main repo | ||||
|           repository: ${{ github.repository }} | ||||
|           ref: ${{ steps.pr.outputs.base_ref }} | ||||
|  | ||||
|       - name: Restore Python | ||||
|         if: steps.pr.outputs.skip != 'true' | ||||
|         uses: ./.github/actions/restore-python | ||||
|         with: | ||||
|           python-version: "3.11" | ||||
|           cache-key: ${{ hashFiles('.cache-key') }} | ||||
|  | ||||
|       - name: Download memory analysis artifacts | ||||
|         if: steps.pr.outputs.skip != 'true' | ||||
|         run: | | ||||
|           run_id="${{ github.event.workflow_run.id }}" | ||||
|           echo "Downloading artifacts from workflow run $run_id" | ||||
|  | ||||
|           mkdir -p memory-analysis | ||||
|  | ||||
|           # Download target analysis artifact | ||||
|           if gh run download --name "memory-analysis-target" --dir memory-analysis --repo "${{ github.repository }}" "$run_id"; then | ||||
|             echo "Downloaded memory-analysis-target artifact." | ||||
|           else | ||||
|             echo "No memory-analysis-target artifact found." | ||||
|           fi | ||||
|  | ||||
|           # Download PR analysis artifact | ||||
|           if gh run download --name "memory-analysis-pr" --dir memory-analysis --repo "${{ github.repository }}" "$run_id"; then | ||||
|             echo "Downloaded memory-analysis-pr artifact." | ||||
|           else | ||||
|             echo "No memory-analysis-pr artifact found." | ||||
|           fi | ||||
|  | ||||
|       - name: Check if artifacts exist | ||||
|         id: check | ||||
|         if: steps.pr.outputs.skip != 'true' | ||||
|         run: | | ||||
|           if [ -f ./memory-analysis/memory-analysis-target.json ] && [ -f ./memory-analysis/memory-analysis-pr.json ]; then | ||||
|             echo "found=true" >> $GITHUB_OUTPUT | ||||
|           else | ||||
|             echo "found=false" >> $GITHUB_OUTPUT | ||||
|             echo "Memory analysis artifacts not found, skipping comment" | ||||
|           fi | ||||
|  | ||||
|       - name: Post or update PR comment | ||||
|         if: steps.pr.outputs.skip != 'true' && steps.check.outputs.found == 'true' | ||||
|         env: | ||||
|           PR_NUMBER: ${{ steps.pr.outputs.pr_number }} | ||||
|         run: | | ||||
|           . venv/bin/activate | ||||
|           # Pass PR number and JSON file paths directly to Python script | ||||
|           # Let Python parse the JSON to avoid shell injection risks | ||||
|           # The script will validate and sanitize all inputs | ||||
|           python script/ci_memory_impact_comment.py \ | ||||
|             --pr-number "$PR_NUMBER" \ | ||||
|             --target-json ./memory-analysis/memory-analysis-target.json \ | ||||
|             --pr-json ./memory-analysis/memory-analysis-pr.json | ||||
							
								
								
									
										65
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -641,6 +641,12 @@ jobs: | ||||
|               --output-env \ | ||||
|               --output-json memory-analysis-target.json | ||||
|  | ||||
|           # Add metadata to JSON before caching | ||||
|           python script/ci_add_metadata_to_json.py \ | ||||
|             --json-file memory-analysis-target.json \ | ||||
|             --components "$components" \ | ||||
|             --platform "$platform" | ||||
|  | ||||
|       - name: Save memory analysis to cache | ||||
|         if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success' | ||||
|         uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | ||||
| @@ -720,6 +726,13 @@ jobs: | ||||
|             python script/ci_memory_impact_extract.py \ | ||||
|               --output-env \ | ||||
|               --output-json memory-analysis-pr.json | ||||
|  | ||||
|           # Add metadata to JSON (components and platform are in shell variables above) | ||||
|           python script/ci_add_metadata_to_json.py \ | ||||
|             --json-file memory-analysis-pr.json \ | ||||
|             --components "$components" \ | ||||
|             --platform "$platform" | ||||
|  | ||||
|       - name: Upload memory analysis JSON | ||||
|         uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||||
|         with: | ||||
| @@ -736,10 +749,12 @@ jobs: | ||||
|       - determine-jobs | ||||
|       - memory-impact-target-branch | ||||
|       - memory-impact-pr-branch | ||||
|     if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true' && needs.memory-impact-target-branch.outputs.skip != 'true' | ||||
|     if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true' && needs.memory-impact-target-branch.outputs.skip != 'true' | ||||
|     permissions: | ||||
|       contents: read | ||||
|       pull-requests: write | ||||
|     env: | ||||
|       GH_TOKEN: ${{ github.token }} | ||||
|     steps: | ||||
|       - name: Check out code | ||||
|         uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | ||||
| @@ -762,52 +777,16 @@ jobs: | ||||
|         continue-on-error: true | ||||
|       - name: Post or update PR comment | ||||
|         env: | ||||
|           GH_TOKEN: ${{ github.token }} | ||||
|           COMPONENTS: ${{ toJSON(fromJSON(needs.determine-jobs.outputs.memory_impact).components) }} | ||||
|           PLATFORM: ${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }} | ||||
|           TARGET_RAM: ${{ needs.memory-impact-target-branch.outputs.ram_usage }} | ||||
|           TARGET_FLASH: ${{ needs.memory-impact-target-branch.outputs.flash_usage }} | ||||
|           PR_RAM: ${{ needs.memory-impact-pr-branch.outputs.ram_usage }} | ||||
|           PR_FLASH: ${{ needs.memory-impact-pr-branch.outputs.flash_usage }} | ||||
|           TARGET_CACHE_HIT: ${{ needs.memory-impact-target-branch.outputs.cache_hit }} | ||||
|           PR_NUMBER: ${{ github.event.pull_request.number }} | ||||
|         run: | | ||||
|           . venv/bin/activate | ||||
|  | ||||
|           # Check if analysis JSON files exist | ||||
|           target_json_arg="" | ||||
|           pr_json_arg="" | ||||
|  | ||||
|           if [ -f ./memory-analysis/memory-analysis-target.json ]; then | ||||
|             echo "Found target analysis JSON" | ||||
|             target_json_arg="--target-json ./memory-analysis/memory-analysis-target.json" | ||||
|           else | ||||
|             echo "No target analysis JSON found" | ||||
|           fi | ||||
|  | ||||
|           if [ -f ./memory-analysis/memory-analysis-pr.json ]; then | ||||
|             echo "Found PR analysis JSON" | ||||
|             pr_json_arg="--pr-json ./memory-analysis/memory-analysis-pr.json" | ||||
|           else | ||||
|             echo "No PR analysis JSON found" | ||||
|           fi | ||||
|  | ||||
|           # Add cache flag if target was cached | ||||
|           cache_flag="" | ||||
|           if [ "$TARGET_CACHE_HIT" == "true" ]; then | ||||
|             cache_flag="--target-cache-hit" | ||||
|           fi | ||||
|  | ||||
|           # Pass JSON file paths directly to Python script | ||||
|           # All data is extracted from JSON files for security | ||||
|           python script/ci_memory_impact_comment.py \ | ||||
|             --pr-number "${{ github.event.pull_request.number }}" \ | ||||
|             --components "$COMPONENTS" \ | ||||
|             --platform "$PLATFORM" \ | ||||
|             --target-ram "$TARGET_RAM" \ | ||||
|             --target-flash "$TARGET_FLASH" \ | ||||
|             --pr-ram "$PR_RAM" \ | ||||
|             --pr-flash "$PR_FLASH" \ | ||||
|             $target_json_arg \ | ||||
|             $pr_json_arg \ | ||||
|             $cache_flag | ||||
|             --pr-number "$PR_NUMBER" \ | ||||
|             --target-json ./memory-analysis/memory-analysis-target.json \ | ||||
|             --pr-json ./memory-analysis/memory-analysis-pr.json | ||||
|  | ||||
|   ci-status: | ||||
|     name: CI Status | ||||
|   | ||||
		Reference in New Issue
	
	Block a user