Skip to content

Commit d1ea2ec

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 d1ea2ec

File tree

1 file changed

+295
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)