-
Notifications
You must be signed in to change notification settings - Fork 226
Add fetch-cache script for collecting cached dep images from GitHub CI #899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,302 @@ | ||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||
|
|
||||||||||||||||
| """ | ||||||||||||||||
| Fetches pre-built dependency images from GitHub Actions artifacts. | ||||||||||||||||
|
|
||||||||||||||||
| This script downloads cached Docker images for quickstart dependencies from | ||||||||||||||||
| the stellar/quickstart CI workflow artifacts, then loads them into Docker | ||||||||||||||||
| with the stage tags expected by the Dockerfile. | ||||||||||||||||
|
|
||||||||||||||||
| Usage: | ||||||||||||||||
| .scripts/fetch-cache --tag nightly --image-json .image.json | ||||||||||||||||
|
|
||||||||||||||||
| Requirements: | ||||||||||||||||
| - gh CLI authenticated with access to stellar/quickstart | ||||||||||||||||
| - docker CLI available | ||||||||||||||||
| """ | ||||||||||||||||
|
|
||||||||||||||||
| import argparse | ||||||||||||||||
| import json | ||||||||||||||||
| import os | ||||||||||||||||
| import platform | ||||||||||||||||
| import subprocess | ||||||||||||||||
| import sys | ||||||||||||||||
| import tempfile | ||||||||||||||||
| from pathlib import Path | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def detect_arch(): | ||||||||||||||||
| """Detect the native architecture (amd64 or arm64).""" | ||||||||||||||||
| machine = platform.machine().lower() | ||||||||||||||||
| if machine in ("x86_64", "amd64"): | ||||||||||||||||
| return "amd64" | ||||||||||||||||
| elif machine in ("arm64", "aarch64"): | ||||||||||||||||
| return "arm64" | ||||||||||||||||
| else: | ||||||||||||||||
| print(f"Warning: Unknown architecture '{machine}', defaulting to amd64", file=sys.stderr) | ||||||||||||||||
| return "amd64" | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def run_cmd(cmd, capture=True, check=True, verbose=True): | ||||||||||||||||
| """Run a command and return output.""" | ||||||||||||||||
| if verbose: | ||||||||||||||||
| print(f" Running: {' '.join(cmd)}", file=sys.stderr) | ||||||||||||||||
| result = subprocess.run( | ||||||||||||||||
| cmd, | ||||||||||||||||
| capture_output=capture, | ||||||||||||||||
| text=True, | ||||||||||||||||
| check=check | ||||||||||||||||
| ) | ||||||||||||||||
| return result.stdout.strip() if capture else None | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def run_cmd_quiet(cmd, check=True): | ||||||||||||||||
| """Run a command quietly, only showing output on failure.""" | ||||||||||||||||
| result = subprocess.run( | ||||||||||||||||
| cmd, | ||||||||||||||||
| capture_output=True, | ||||||||||||||||
| text=True, | ||||||||||||||||
| check=False | ||||||||||||||||
| ) | ||||||||||||||||
| if check and result.returncode != 0: | ||||||||||||||||
| print(f"Command failed: {' '.join(cmd)}", file=sys.stderr) | ||||||||||||||||
| print(f"stdout: {result.stdout}", file=sys.stderr) | ||||||||||||||||
| print(f"stderr: {result.stderr}", file=sys.stderr) | ||||||||||||||||
| raise subprocess.CalledProcessError(result.returncode, cmd) | ||||||||||||||||
|
||||||||||||||||
| raise subprocess.CalledProcessError(result.returncode, cmd) | |
| raise subprocess.CalledProcessError( | |
| result.returncode, | |
| cmd, | |
| output=result.stdout, | |
| stderr=result.stderr, | |
| ) |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the artifact pagination loop, if an exception occurs (line 126-128), the loop breaks and returns whatever artifacts were collected so far. This is appropriate for handling transient errors, but it means partial results could be silently returned if there are more artifacts available. Consider logging a warning that indicates how many pages were successfully processed before the error, so users understand if they're getting incomplete results.
| print(f" Warning: Failed to list artifacts (page {page}): {e}", file=sys.stderr) | |
| print( | |
| f" Warning: Failed to list artifacts for run {run_id} on page {page}: {e}. " | |
| f"Returning {len(all_artifacts)} artifact(s) collected from previous page(s).", | |
| file=sys.stderr, | |
| ) |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When downloading artifacts, the script creates subdirectories in the temp directory using user-controlled input (dep_name). While tempfile.TemporaryDirectory() provides a secure temp directory, the dep_name comes from the image.json file which could theoretically contain path traversal characters. Although this is unlikely in practice since the image.json is part of the repository, consider sanitizing dep_name before using it in path construction to prevent potential path traversal issues (e.g., if dep_name contained '../').
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The run_cmd function has a 'verbose' parameter that defaults to True, printing every command to stderr. This could be excessive for operations that run many times (like API calls for pagination). The verbose output is helpful for debugging but may clutter the output during normal operation. Consider making verbosity configurable via a command-line flag or at least reducing verbosity for repetitive operations like pagination.