Skip to content

Commit 540fb3f

Browse files
committed
ci: Add an action to publish FW blob information
This is based on manifest GH action in Zephyr and publishes the blob information. Signed-off-by: Chaitanya Tata <[email protected]>
1 parent ee35b36 commit 540fb3f

File tree

1 file changed

+292
-0
lines changed

1 file changed

+292
-0
lines changed
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
name: Module Monitor
2+
on:
3+
push:
4+
paths:
5+
- 'zephyr/module.yml'
6+
pull_request_target:
7+
paths:
8+
- 'zephyr/module.yml'
9+
10+
permissions:
11+
contents: read
12+
pull-requests: write
13+
14+
jobs:
15+
module-monitor:
16+
runs-on: ubuntu-24.04
17+
name: Monitor Module Changes
18+
steps:
19+
- name: Checkout the code
20+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
21+
with:
22+
fetch-depth: 0
23+
persist-credentials: false
24+
25+
- name: Set up Python
26+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
27+
with:
28+
python-version: 3.12
29+
cache: pip
30+
31+
- name: Install PyYAML
32+
run: |
33+
pip install pyyaml
34+
35+
- name: Get module.yml changes and blob info
36+
id: changes
37+
run: |
38+
# For pull requests, compare with base branch
39+
if [ "${{ github.event_name }}" = "pull_request" ]; then
40+
BASE_REF="${{ github.event.pull_request.base.sha }}"
41+
HEAD_REF="${{ github.event.pull_request.head.sha }}"
42+
DIFF_OUTPUT=$(git diff $BASE_REF $HEAD_REF -- zephyr/module.yml || echo "No changes found")
43+
else
44+
# For push events, get the previous commit that modified module.yml
45+
PREV_COMMIT=$(git log --oneline --follow -- zephyr/module.yml | head -2 | tail -1 | cut -d' ' -f1)
46+
if [ -n "$PREV_COMMIT" ]; then
47+
DIFF_OUTPUT=$(git diff $PREV_COMMIT HEAD -- zephyr/module.yml || echo "No changes found")
48+
else
49+
DIFF_OUTPUT="No previous commit found for module.yml"
50+
fi
51+
fi
52+
53+
echo "diff_output<<EOF" >> $GITHUB_OUTPUT
54+
echo "$DIFF_OUTPUT" >> $GITHUB_OUTPUT
55+
echo "EOF" >> $GITHUB_OUTPUT
56+
57+
# Parse YAML and extract blob information with version comparison
58+
python3 << 'EOF'
59+
import yaml
60+
import sys
61+
import os
62+
import re
63+
import requests
64+
from urllib.parse import urlparse
65+
66+
def extract_commit_from_url(url):
67+
"""Extract commit hash from GitHub URL"""
68+
# Pattern for GitHub raw URLs with commit hash
69+
pattern = r'raw/([a-f0-9]{40})/'
70+
match = re.search(pattern, url)
71+
if match:
72+
return match.group(1)
73+
return None
74+
75+
def get_github_api_url(url):
76+
"""Convert raw GitHub URL to API URL to get file info"""
77+
# Convert: https://github.com/nrfconnect/sdk-nrfxlib/raw/commit/bin/file.bin
78+
# To: https://api.github.com/repos/nrfconnect/sdk-nrfxlib/git/blobs/commit
79+
pattern = r'github\.com/([^/]+/[^/]+)/raw/([a-f0-9]{40})/(.+)'
80+
match = re.search(pattern, url)
81+
if match:
82+
repo = match.group(1)
83+
commit = match.group(2)
84+
path = match.group(3)
85+
return f"https://api.github.com/repos/{repo}/contents/{path}?ref={commit}"
86+
return None
87+
88+
try:
89+
# Read current module.yml
90+
with open('zephyr/module.yml', 'r') as f:
91+
current_data = yaml.safe_load(f)
92+
93+
# Read previous module.yml if it exists
94+
previous_data = None
95+
if "${{ github.event_name }}" == "pull_request":
96+
# For PR, we need to checkout the base branch to get previous data
97+
os.system("git checkout ${{ github.event.pull_request.base.sha }} -- zephyr/module.yml")
98+
if os.path.exists('zephyr/module.yml'):
99+
with open('zephyr/module.yml', 'r') as f:
100+
previous_data = yaml.safe_load(f)
101+
# Restore current version
102+
os.system("git checkout ${{ github.event.pull_request.head.sha }} -- zephyr/module.yml")
103+
else:
104+
# For push, get previous commit
105+
prev_commit = os.popen("git log --oneline --follow -- zephyr/module.yml | head -2 | tail -1 | cut -d' ' -f1").read().strip()
106+
if prev_commit:
107+
os.system(f"git show {prev_commit}:zephyr/module.yml > /tmp/previous_module.yml")
108+
if os.path.exists('/tmp/previous_module.yml'):
109+
with open('/tmp/previous_module.yml', 'r') as f:
110+
previous_data = yaml.safe_load(f)
111+
112+
# Create comparison table
113+
table_rows = []
114+
current_blobs = current_data.get('blobs', [])
115+
previous_blobs = previous_data.get('blobs', []) if previous_data else []
116+
117+
# Create lookup for previous blobs
118+
prev_lookup = {}
119+
for blob in previous_blobs:
120+
path = blob.get('path', '')
121+
prev_lookup[path] = blob
122+
123+
for blob in current_blobs:
124+
path = blob.get('path', 'Unknown')
125+
current_version = blob.get('version', 'Unknown')
126+
current_sha256 = blob.get('sha256', 'Unknown')
127+
current_url = blob.get('url', '')
128+
129+
# Extract variant name from path
130+
variant = path.split('/')[-2] if '/' in path else 'Unknown'
131+
132+
# Get previous info
133+
prev_blob = prev_lookup.get(path, {})
134+
prev_version = prev_blob.get('version', 'N/A')
135+
prev_sha256 = prev_blob.get('sha256', 'N/A')
136+
137+
# Extract commit from URL
138+
commit = extract_commit_from_url(current_url)
139+
commit_short = commit[:8] if commit else 'N/A'
140+
141+
# Create diff link if we have both URLs
142+
prev_url = prev_blob.get('url', '')
143+
if prev_url and current_url and prev_url != current_url:
144+
# Extract repo info for diff link
145+
repo_match = re.search(r'github\.com/([^/]+/[^/]+)/', current_url)
146+
if repo_match:
147+
repo = repo_match.group(1)
148+
diff_link = f"https://github.com/{repo}/compare/{extract_commit_from_url(prev_url)[:8]}...{commit_short}"
149+
else:
150+
diff_link = "N/A"
151+
else:
152+
diff_link = "N/A"
153+
154+
table_rows.append({
155+
'variant': variant,
156+
'old_version': prev_version,
157+
'new_version': current_version,
158+
'old_sha256': prev_sha256[:16] + '...' if len(prev_sha256) > 16 else prev_sha256,
159+
'new_sha256': current_sha256[:16] + '...' if len(current_sha256) > 16 else current_sha256,
160+
'commit': commit_short,
161+
'diff_link': diff_link
162+
})
163+
164+
# Generate table output
165+
print("blob_table<<EOF", file=sys.stdout)
166+
if table_rows:
167+
print("| Variant | Old Version | New Version | Old SHA256 | New SHA256 | Commit | Diff |", file=sys.stdout)
168+
print("|---------|-------------|-------------|------------|------------|--------|------|", file=sys.stdout)
169+
for row in table_rows:
170+
diff_markdown = f"[{row['commit']}]({row['diff_link']})" if row['diff_link'] != "N/A" else "N/A"
171+
print(f"| {row['variant']} | {row['old_version']} | {row['new_version']} | {row['old_sha256']} | {row['new_sha256']} | {row['commit']} | {diff_markdown} |", file=sys.stdout)
172+
else:
173+
print("No firmware blob changes detected.", file=sys.stdout)
174+
print("EOF", file=sys.stdout)
175+
176+
# Also generate current blob summary
177+
if current_blobs:
178+
blob_info = []
179+
for blob in current_blobs:
180+
info = f"- **{blob.get('path', 'Unknown')}**\n"
181+
info += f" - Version: {blob.get('version', 'Unknown')}\n"
182+
info += f" - SHA256: {blob.get('sha256', 'Unknown')[:16]}...\n"
183+
info += f" - Type: {blob.get('type', 'Unknown')}\n"
184+
info += f" - Description: {blob.get('description', 'No description')}\n"
185+
blob_info.append(info)
186+
187+
print("blob_summary<<EOF", file=sys.stdout)
188+
print("## Current Firmware Blobs:", file=sys.stdout)
189+
for info in blob_info:
190+
print(info, file=sys.stdout)
191+
print("EOF", file=sys.stdout)
192+
else:
193+
print("blob_summary<<EOF", file=sys.stdout)
194+
print("No blobs found in module.yml", file=sys.stdout)
195+
print("EOF", file=sys.stdout)
196+
197+
except Exception as e:
198+
print("blob_table<<EOF", file=sys.stdout)
199+
print(f"Error generating blob table: {e}", file=sys.stdout)
200+
print("EOF", file=sys.stdout)
201+
print("blob_summary<<EOF", file=sys.stdout)
202+
print(f"Error parsing module.yml: {e}", file=sys.stdout)
203+
print("EOF", file=sys.stdout)
204+
EOF
205+
206+
- name: Create or update comment (Pull Request)
207+
if: github.event_name == 'pull_request'
208+
uses: actions/github-script@d7906e4ad0b1822421a7e57a40e5a1d82c19f2a5 # v7.0.1
209+
with:
210+
script: |
211+
const { data: comments } = await github.rest.issues.listComments({
212+
owner: context.repo.owner,
213+
repo: context.repo.repo,
214+
issue_number: context.issue.number
215+
});
216+
217+
// Find existing comment with our signature
218+
const existingComment = comments.find(comment =>
219+
comment.body.includes('🤖 **Module Monitor**')
220+
);
221+
222+
const commentBody = `🤖 **Module Monitor**
223+
224+
## Firmware Blob Changes
225+
226+
The following firmware blobs have changed in this update:
227+
228+
${process.env.blob_table || 'No changes detected'}
229+
230+
${process.env.blob_summary || ''}
231+
232+
---
233+
*This comment was automatically generated by the Module Monitor workflow*`;
234+
235+
if (existingComment) {
236+
// Update existing comment
237+
await github.rest.issues.updateComment({
238+
owner: context.repo.owner,
239+
repo: context.repo.repo,
240+
comment_id: existingComment.id,
241+
body: commentBody
242+
});
243+
} else {
244+
// Create new comment
245+
await github.rest.issues.createComment({
246+
owner: context.repo.owner,
247+
repo: context.repo.repo,
248+
issue_number: context.issue.number,
249+
body: commentBody
250+
});
251+
}
252+
env:
253+
blob_table: ${{ steps.changes.outputs.blob_table }}
254+
blob_summary: ${{ steps.changes.outputs.blob_summary }}
255+
256+
- name: Create commit comment (Push)
257+
if: github.event_name == 'push'
258+
uses: actions/github-script@d7906e4ad0b1822421a7e57a40e5a1d82c19f2a5 # v7.0.1
259+
with:
260+
script: |
261+
const commentBody = `🤖 **Module Monitor**
262+
263+
## Firmware Blob Changes
264+
265+
The following firmware blobs have changed in this update:
266+
267+
${process.env.blob_table || 'No changes detected'}
268+
269+
${process.env.blob_summary || ''}
270+
271+
---
272+
*This comment was automatically generated by the Module Monitor workflow*`;
273+
274+
await github.rest.repos.createCommitComment({
275+
owner: context.repo.owner,
276+
repo: context.repo.repo,
277+
commit_sha: context.sha,
278+
body: commentBody
279+
});
280+
env:
281+
blob_table: ${{ steps.changes.outputs.blob_table }}
282+
blob_summary: ${{ steps.changes.outputs.blob_summary }}
283+
284+
- name: Output summary
285+
run: |
286+
echo "## Module Monitor Summary" >> $GITHUB_STEP_SUMMARY
287+
echo "" >> $GITHUB_STEP_SUMMARY
288+
echo "### Firmware Blob Changes:" >> $GITHUB_STEP_SUMMARY
289+
echo "" >> $GITHUB_STEP_SUMMARY
290+
echo "${{ steps.changes.outputs.blob_table }}" >> $GITHUB_STEP_SUMMARY
291+
echo "" >> $GITHUB_STEP_SUMMARY
292+
echo "${{ steps.changes.outputs.blob_summary }}" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)