Skip to content

Commit c6815c7

Browse files
authored
Update component version (#1382)
* Add download_github_runs.py * Update esp-ml307 version * Update esp-sr to 2.2.0
1 parent 0e51c4c commit c6815c7

File tree

2 files changed

+266
-2
lines changed

2 files changed

+266
-2
lines changed

main/idf_component.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ dependencies:
2020
78/esp_lcd_nv3023: ~1.0.0
2121
78/esp-wifi-connect: ~2.6.1
2222
78/esp-opus-encoder: ~2.4.1
23-
78/esp-ml307: ~3.3.6
23+
78/esp-ml307: ~3.3.7
2424
78/xiaozhi-fonts: ~1.5.4
2525
espressif/led_strip: ~3.0.1
2626
espressif/esp_codec_dev: ~1.5
27-
espressif/esp-sr: ~2.1.5
27+
espressif/esp-sr: ~2.2.0
2828
espressif/button: ~4.1.3
2929
espressif/knob: ^1.0.0
3030
espressif/esp_video:

scripts/download_github_runs.py

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Download GitHub Actions artifacts and rename them with version numbers.
4+
5+
Usage:
6+
python download_github_runs.py 2.0.4 https://github.com/78/xiaozhi-esp32/actions/runs/18866246016
7+
"""
8+
9+
import argparse
10+
import os
11+
import re
12+
import sys
13+
import zipfile
14+
from pathlib import Path
15+
from urllib.parse import urlparse
16+
17+
import requests
18+
from dotenv import load_dotenv
19+
20+
21+
def parse_github_run_url(url: str) -> tuple[str, str, str]:
22+
"""
23+
Parse GitHub Actions run URL to extract owner, repo, and run_id.
24+
25+
Args:
26+
url: GitHub Actions run URL
27+
28+
Returns:
29+
Tuple of (owner, repo, run_id)
30+
"""
31+
# Example: https://github.com/78/xiaozhi-esp32/actions/runs/18866246016
32+
pattern = r'github\.com/([^/]+)/([^/]+)/actions/runs/(\d+)'
33+
match = re.search(pattern, url)
34+
35+
if not match:
36+
raise ValueError(f"Invalid GitHub Actions URL: {url}")
37+
38+
owner, repo, run_id = match.groups()
39+
return owner, repo, run_id
40+
41+
42+
def get_artifacts(owner: str, repo: str, run_id: str, token: str) -> list[dict]:
43+
"""
44+
Get all artifacts for a specific workflow run (with pagination support).
45+
46+
Args:
47+
owner: Repository owner
48+
repo: Repository name
49+
run_id: Workflow run ID
50+
token: GitHub personal access token
51+
52+
Returns:
53+
List of artifact dictionaries
54+
"""
55+
headers = {
56+
"Authorization": f"Bearer {token}",
57+
"Accept": "application/vnd.github+json",
58+
"X-GitHub-Api-Version": "2022-11-28"
59+
}
60+
61+
all_artifacts = []
62+
page = 1
63+
per_page = 100 # Maximum allowed by GitHub API
64+
65+
while True:
66+
url = f"https://api.github.com/repos/{owner}/{repo}/actions/runs/{run_id}/artifacts"
67+
params = {
68+
"page": page,
69+
"per_page": per_page
70+
}
71+
72+
response = requests.get(url, headers=headers, params=params)
73+
response.raise_for_status()
74+
75+
data = response.json()
76+
artifacts = data.get("artifacts", [])
77+
78+
if not artifacts:
79+
break
80+
81+
all_artifacts.extend(artifacts)
82+
83+
# Check if there are more pages
84+
total_count = data.get("total_count", 0)
85+
if len(all_artifacts) >= total_count:
86+
break
87+
88+
page += 1
89+
90+
return all_artifacts
91+
92+
93+
def download_artifact(artifact_url: str, token: str, output_path: Path) -> None:
94+
"""
95+
Download an artifact from GitHub.
96+
97+
Args:
98+
artifact_url: Artifact download URL
99+
token: GitHub personal access token
100+
output_path: Path to save the downloaded artifact
101+
"""
102+
headers = {
103+
"Authorization": f"Bearer {token}",
104+
"Accept": "application/vnd.github+json",
105+
"X-GitHub-Api-Version": "2022-11-28"
106+
}
107+
108+
response = requests.get(artifact_url, headers=headers, stream=True)
109+
response.raise_for_status()
110+
111+
# Create parent directory if it doesn't exist
112+
output_path.parent.mkdir(parents=True, exist_ok=True)
113+
114+
# Download the file
115+
with open(output_path, 'wb') as f:
116+
for chunk in response.iter_content(chunk_size=8192):
117+
if chunk:
118+
f.write(chunk)
119+
120+
121+
def rename_artifact(original_name: str, version: str) -> str:
122+
"""
123+
Rename artifact according to the specified rules.
124+
125+
Rules:
126+
- Remove "xiaozhi_" prefix
127+
- Remove hash suffix (underscore followed by hex string)
128+
- Add version prefix (e.g., "v2.0.4_")
129+
- Change extension to .zip
130+
131+
Example:
132+
xiaozhi_atk-dnesp32s3-box0_43ef2f4e7f0957dc62ec7d628ac2819d226127b8.bin
133+
-> v2.0.4_atk-dnesp32s3-box0.zip
134+
135+
Args:
136+
original_name: Original artifact name
137+
version: Version string (e.g., "2.0.4")
138+
139+
Returns:
140+
New filename
141+
"""
142+
# Remove "xiaozhi_" prefix
143+
name = original_name
144+
if name.startswith("xiaozhi_"):
145+
name = name[len("xiaozhi_"):]
146+
147+
# Remove extension
148+
name_without_ext = os.path.splitext(name)[0]
149+
150+
# Remove hash suffix (pattern: underscore followed by 40+ hex characters)
151+
# This matches Git commit hashes and similar identifiers
152+
name_without_hash = re.sub(r'_[a-f0-9]{40,}$', '', name_without_ext)
153+
154+
# Add version prefix and .zip extension
155+
new_name = f"v{version}_{name_without_hash}.zip"
156+
157+
return new_name
158+
159+
160+
def main():
161+
"""Main function to download and rename GitHub Actions artifacts."""
162+
parser = argparse.ArgumentParser(
163+
description="Download GitHub Actions artifacts and rename them with version numbers."
164+
)
165+
parser.add_argument(
166+
"version",
167+
help="Version number (e.g., 2.0.4)"
168+
)
169+
parser.add_argument(
170+
"url",
171+
help="GitHub Actions run URL (e.g., https://github.com/owner/repo/actions/runs/12345)"
172+
)
173+
parser.add_argument(
174+
"--output-dir",
175+
default="../releases",
176+
help="Output directory for downloaded artifacts (default: ../releases)"
177+
)
178+
179+
args = parser.parse_args()
180+
181+
# Load GitHub token from .env file
182+
load_dotenv()
183+
github_token = os.getenv("GITHUB_TOKEN")
184+
185+
if not github_token:
186+
print("Error: GITHUB_TOKEN not found in environment variables.", file=sys.stderr)
187+
print("Please create a .env file with GITHUB_TOKEN=your_token_here", file=sys.stderr)
188+
sys.exit(1)
189+
190+
try:
191+
# Parse the GitHub URL
192+
owner, repo, run_id = parse_github_run_url(args.url)
193+
print(f"Repository: {owner}/{repo}")
194+
print(f"Run ID: {run_id}")
195+
print(f"Version: {args.version}")
196+
print()
197+
198+
# Get artifacts
199+
print("Fetching artifacts...")
200+
artifacts = get_artifacts(owner, repo, run_id, github_token)
201+
202+
if not artifacts:
203+
print("No artifacts found for this run.")
204+
return
205+
206+
print(f"Found {len(artifacts)} artifact(s):")
207+
for artifact in artifacts:
208+
print(f" - {artifact['name']}")
209+
print()
210+
211+
# Create output directory
212+
output_dir = Path(args.output_dir)
213+
output_dir.mkdir(parents=True, exist_ok=True)
214+
215+
# Download and rename each artifact
216+
downloaded_count = 0
217+
skipped_count = 0
218+
219+
for artifact in artifacts:
220+
original_name = artifact['name']
221+
new_name = rename_artifact(original_name, args.version)
222+
final_path = output_dir / new_name
223+
224+
# Check if file already exists
225+
if final_path.exists():
226+
print(f"Skipping (already exists): {original_name}")
227+
print(f" -> {new_name}")
228+
print(f" File: {final_path}")
229+
print()
230+
skipped_count += 1
231+
continue
232+
233+
print(f"Downloading: {original_name}")
234+
print(f" -> {new_name}")
235+
236+
# Download to temporary path first
237+
temp_path = output_dir / f"{original_name}.zip"
238+
download_artifact(
239+
artifact['archive_download_url'],
240+
github_token,
241+
temp_path
242+
)
243+
244+
# Rename to final name
245+
temp_path.rename(final_path)
246+
247+
print(f" Saved to: {final_path}")
248+
print()
249+
downloaded_count += 1
250+
251+
print(f"Summary:")
252+
print(f" Downloaded: {downloaded_count} artifact(s)")
253+
print(f" Skipped: {skipped_count} artifact(s)")
254+
print(f" Total: {len(artifacts)} artifact(s)")
255+
print(f" Output directory: {output_dir.absolute()}")
256+
257+
except Exception as e:
258+
print(f"Error: {e}", file=sys.stderr)
259+
sys.exit(1)
260+
261+
262+
if __name__ == "__main__":
263+
main()
264+

0 commit comments

Comments
 (0)