Skip to content

Commit fb2f696

Browse files
committed
scripts: Add PR information
In case of a PR, add a reference for CI parsing. Signed-off-by: Chaitanya Tata <[email protected]>
1 parent 7acba70 commit fb2f696

File tree

1 file changed

+116
-13
lines changed

1 file changed

+116
-13
lines changed

scripts/update_blobs.py

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
import hashlib
1515
import requests
1616
import logging
17+
import os
1718
from jinja2 import Environment, FileSystemLoader
18-
from typing import Dict, Any, List
19+
from typing import Dict, Any, List, Optional
1920
from collections import namedtuple
2021

2122
WIFI_FW_BIN_NAME: str = "nrf70.bin"
@@ -71,14 +72,56 @@ def get_wifi_blob_info(name: str) -> BlobInfo:
7172
logging.basicConfig(level=logging.INFO)
7273

7374

75+
def get_pr_head_commit(pr_number: str) -> str:
76+
"""Get the head commit SHA for a PR from GitHub API"""
77+
github_token = os.environ.get('GITHUB_TOKEN')
78+
headers = {}
79+
if github_token:
80+
headers['Authorization'] = f'token {github_token}'
81+
82+
url = f"https://api.github.com/repos/nrfconnect/sdk-nrfxlib/pulls/{pr_number}"
83+
84+
try:
85+
response = requests.get(url, headers=headers, timeout=30)
86+
response.raise_for_status()
87+
88+
pr_data = response.json()
89+
90+
# Check if PR exists and is not closed/merged
91+
if pr_data.get('state') == 'closed':
92+
logger.warning(f"PR #{pr_number} is closed")
93+
94+
if pr_data.get('merged'):
95+
logger.warning(f"PR #{pr_number} is already merged")
96+
97+
# Get head commit
98+
head_commit = pr_data['head']['sha']
99+
if not head_commit:
100+
raise ValueError(f"PR #{pr_number} has no head commit")
101+
102+
logger.info(f"PR #{pr_number} head commit: {head_commit}")
103+
return head_commit
104+
105+
except requests.exceptions.RequestException as e:
106+
if response.status_code == 404:
107+
raise ValueError(f"PR #{pr_number} not found in nrfconnect/sdk-nrfxlib repository")
108+
elif response.status_code == 403:
109+
raise ValueError(f"Access denied to PR #{pr_number}. Check GITHUB_TOKEN permissions")
110+
else:
111+
raise ValueError(f"Failed to fetch PR #{pr_number}: {e}")
112+
except KeyError as e:
113+
raise ValueError(f"Invalid response format for PR #{pr_number}: missing {e}")
114+
except Exception as e:
115+
raise ValueError(f"Unexpected error fetching PR #{pr_number}: {e}")
116+
74117
def compute_sha256(url: str) -> str:
75118
response = requests.get(url)
76119
response.raise_for_status()
77120
sha256_hash: str = hashlib.sha256(response.content).hexdigest()
78121
return sha256_hash
79122

80123

81-
def render_template(template_path: str, output_path: str, latest_sha: str) -> None:
124+
def render_template(template_path: str, output_path: str, latest_sha: str, is_pr: bool = False, pr_number: Optional[str] = None) -> None:
82125
# Load the Jinja2 template
83126
env: Environment = Environment(loader=FileSystemLoader("."))
84127
template = env.get_template(template_path)
@@ -97,24 +140,41 @@ def render_template(template_path: str, output_path: str, latest_sha: str) -> No
97140
blob_info["doc_url"] = f"{blob.docpath}"
98141

99142
# Download the binary to compute SHA-256 and extract version
100-
response = requests.get(blob_info["url"])
101-
response.raise_for_status()
102-
binary_data = response.content
143+
try:
144+
response = requests.get(blob_info["url"], timeout=60)
145+
response.raise_for_status()
146+
binary_data = response.content
147+
148+
blob_info["sha256"] = hashlib.sha256(binary_data).hexdigest()
149+
blob_info["description"] = blob.description
103150

104-
blob_info["sha256"] = hashlib.sha256(binary_data).hexdigest()
105-
blob_info["description"] = blob.description
151+
# Parse version from the actual binary
152+
blob_info["version"] = parse_version_from_binary(binary_data)
106153

107-
# Parse version from the actual binary
108-
blob_info["version"] = parse_version_from_binary(binary_data)
154+
except requests.exceptions.RequestException as e:
155+
logger.error(f"Failed to download blob from {blob_info['url']}: {e}")
156+
raise ValueError(f"Failed to download blob for {blob.name}: {e}")
157+
except Exception as e:
158+
logger.error(f"Unexpected error processing blob {blob.name}: {e}")
159+
raise ValueError(f"Error processing blob {blob.name}: {e}")
109160

110161
blobs[blob.name] = blob_info
111162

112163
logger.debug(blobs)
113164
# Render the template with the provided context
114165
rendered_content: str = template.render(blobs=blobs, latest_sha=latest_sha)
115166

167+
# Add metadata comment at the top
168+
metadata_lines = []
169+
if is_pr and pr_number:
170+
metadata_lines.append(f"# Generated from PR #{pr_number} (commit: {latest_sha})")
171+
else:
172+
metadata_lines.append(f"# Generated from commit: {latest_sha}")
173+
metadata_lines.append("")
174+
116175
# Write the rendered content to the output file
117176
with open(output_path, "w") as output_file:
177+
output_file.writelines(metadata_lines)
118178
output_file.write(rendered_content)
119179

120180

@@ -137,8 +197,12 @@ def main() -> None:
137197
parser.add_argument(
138198
"-c",
139199
"--commit",
140-
required=True,
141-
help="The latest commit SHA for the nrfxlib repository.",
200+
help="The commit SHA for the nrfxlib repository (for merged commits).",
201+
)
202+
parser.add_argument(
203+
"-p",
204+
"--pr",
205+
help="The PR number for the nrfxlib repository (for unmerged PRs).",
142206
)
143207
parser.add_argument(
144208
"-d", "--debug", action="store_true", help="Enable debug logging."
@@ -149,8 +213,47 @@ def main() -> None:
149213
if args.debug:
150214
logger.setLevel(logging.DEBUG)
151215

152-
# Render the template
153-
render_template(args.template, args.output, args.commit)
216+
# Validate arguments
217+
if not args.commit and not args.pr:
218+
parser.error("Either --commit or --pr must be specified")
219+
if args.commit and args.pr:
220+
parser.error("Only one of --commit or --pr can be specified")
221+
222+
# Validate commit format if provided
223+
if args.commit:
224+
import re
225+
if not re.match(r'^[a-fA-F0-9]{7,40}$', args.commit):
226+
parser.error(f"Invalid commit hash format: {args.commit}. Expected 7-40 hex characters.")
227+
228+
# Validate PR number if provided
229+
if args.pr:
230+
if not args.pr.isdigit() or int(args.pr) <= 0:
231+
parser.error(f"Invalid PR number: {args.pr}. Expected a positive integer.")
232+
233+
# Determine the reference to use
234+
try:
235+
if args.pr:
236+
# For PRs, get the head commit from GitHub API
237+
logger.info(f"Processing PR #{args.pr}")
238+
reference = get_pr_head_commit(args.pr)
239+
is_pr = True
240+
pr_number = args.pr
241+
else:
242+
# For merged commits, use the commit hash directly
243+
logger.info(f"Processing commit {args.commit}")
244+
reference = args.commit
245+
is_pr = False
246+
pr_number = None
247+
248+
# Render the template
249+
render_template(args.template, args.output, reference, is_pr, pr_number)
250+
251+
except ValueError as e:
252+
logger.error(f"Error: {e}")
253+
exit(1)
254+
except Exception as e:
255+
logger.error(f"Unexpected error: {e}")
256+
exit(1)
154257

155258

156259
if __name__ == "__main__":

0 commit comments

Comments
 (0)