-
Notifications
You must be signed in to change notification settings - Fork 429
test: set up itk nightly runs #1052
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
Open
kdziedzic70
wants to merge
1
commit into
main
Choose a base branch
from
dziedzick/itk-nightyly
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+294
−78
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| name: Nightly ITK | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 2 * * *' # 2:00 AM UTC daily | ||
| workflow_dispatch: # Allow manual execution | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| nightly: | ||
| name: Nightly ITK Run | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v7 | ||
|
|
||
| - name: Run Nightly ITK Tests | ||
| run: bash run_itk.sh | ||
| working-directory: itk | ||
| env: | ||
| A2A_SAMPLES_REVISION: itk-v.021-alpha | ||
| ITK_NIGHTLY_RUN: "True" | ||
|
|
||
| - name: Upload Results to Rolling Release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: "nightly-metrics" | ||
| prerelease: true | ||
| files: | | ||
| itk/itk_python.json | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| #!/usr/bin/env python3 | ||
| """ITK Compatibility Metrics Processor. | ||
|
|
||
| Compiles test outcomes from raw JSON results, retrieves and aggregates historical | ||
| runs from GitHub Release assets, and outputs the updated historical metrics log. | ||
| """ | ||
|
|
||
| import datetime | ||
| import json | ||
| import logging | ||
| import os | ||
| import pathlib | ||
| import sys | ||
| import urllib.error | ||
| import urllib.request | ||
|
|
||
|
|
||
| # --- CONSTANTS --- | ||
| RESULTS_FILE = 'raw_results.json' | ||
| HISTORY_OUTPUT_FILE = 'itk_python.json' | ||
| HISTORY_URL = 'https://github.com/a2aproject/a2a-python/releases/download/nightly-metrics/itk_python.json' | ||
| SCENARIOS_FILE = 'scenarios.json' | ||
| DEFAULT_HISTORY_LIMIT = 50 | ||
|
|
||
| HTTP_STATUS_OK = 200 | ||
| HTTP_STATUS_NOT_FOUND = 404 | ||
|
|
||
| # Configure logging to match standard ITK formatting | ||
| logging.basicConfig( | ||
| level=logging.INFO, | ||
| ) | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def load_raw_results(filepath: str) -> dict: | ||
| """Loads the raw compatibility results from raw_results.json.""" | ||
| path = pathlib.Path(filepath) | ||
| if not path.exists(): | ||
| logger.error('Results file %s not found.', filepath) | ||
| raise SystemExit(1) | ||
|
|
||
| try: | ||
| with path.open() as f: | ||
| return json.load(f) | ||
| except (OSError, json.JSONDecodeError): | ||
| logger.exception('Error loading results JSON') | ||
| raise SystemExit(1) from None | ||
|
|
||
|
|
||
| def fetch_existing_history(url: str) -> list: | ||
| """Fetches the existing compatibility history from the GitHub release asset. | ||
|
|
||
| If the asset does not exist (HTTP 404), a fresh empty history list is returned. | ||
| For all other network or server errors, the script exits with a non-zero status | ||
| to prevent overwriting and losing historical metrics. | ||
| """ | ||
| try: | ||
| req = urllib.request.Request( # noqa: S310 | ||
| url, headers={'User-Agent': 'Mozilla/5.0'} | ||
| ) | ||
| with urllib.request.urlopen(req, timeout=15) as response: # noqa: S310 | ||
| if response.status == HTTP_STATUS_OK: | ||
| history = json.loads(response.read().decode('utf-8')) | ||
| logger.info( | ||
| 'Successfully retrieved history. Current entries: %d', | ||
| len(history), | ||
| ) | ||
| return history | ||
| logger.error( | ||
| 'Unexpected HTTP status when downloading existing history: %d', | ||
| response.status, | ||
| ) | ||
| raise SystemExit(1) # noqa: TRY301 | ||
| except urllib.error.HTTPError as e: | ||
| if e.code == HTTP_STATUS_NOT_FOUND: | ||
| logger.warning( | ||
| 'No existing history found (HTTP %d). Initializing fresh history.', | ||
| e.code, | ||
| ) | ||
| return [] | ||
| logger.exception( | ||
| 'HTTP error downloading existing history: %d. Aborting to preserve metrics.', | ||
| e.code, | ||
| ) | ||
| raise SystemExit(1) from None | ||
| except Exception: | ||
| logger.exception( | ||
| 'Failed to download existing history. Aborting to preserve metrics.' | ||
| ) | ||
| raise SystemExit(1) from None | ||
|
|
||
|
|
||
| def load_scenarios(filepath: str) -> list: | ||
| """Loads the list of tests from the scenarios.json definitions.""" | ||
| path = pathlib.Path(filepath) | ||
| if not path.exists(): | ||
| logger.error('Scenarios file %s not found.', filepath) | ||
| raise SystemExit(1) | ||
|
|
||
| try: | ||
| with path.open() as f: | ||
| data = json.load(f) | ||
| return data['tests'] | ||
| except (OSError, json.JSONDecodeError, KeyError): | ||
| logger.exception('Failed to load scenarios.json definitions') | ||
| raise SystemExit(1) from None | ||
|
|
||
|
|
||
| def save_history(filepath: str, history: list) -> None: | ||
| """Saves the updated history back to disk as a release asset candidate.""" | ||
| path = pathlib.Path(filepath) | ||
| try: | ||
| with path.open('w') as f: | ||
| json.dump(history, f, indent=2) | ||
| logger.info( | ||
| 'Successfully compiled and wrote nightly history to: %s', | ||
| filepath, | ||
| ) | ||
| except (OSError, TypeError): | ||
| logger.exception('Error writing history file') | ||
| sys.exit(1) | ||
|
|
||
|
|
||
| def main() -> None: | ||
| """Orchestrates nightly ITK metrics processing and compiles rolling history.""" | ||
| # 1. Load raw compatibility results | ||
| data = load_raw_results(RESULTS_FILE) | ||
| all_passed = data.get('all_passed', False) | ||
| results = data.get('results', {}) | ||
|
|
||
| # 2. Fetch existing history from rolling release | ||
| history = fetch_existing_history(HISTORY_URL) | ||
|
|
||
| # 3. Load scenarios list for metadata | ||
| scenarios_list = load_scenarios(SCENARIOS_FILE) | ||
|
|
||
| # Merge definitions with current outcomes | ||
| compiled_scenarios = [] | ||
| for scenario in scenarios_list: | ||
| name = scenario.get('name') | ||
| passed = results.get(name, False) | ||
| combined = dict(scenario) | ||
| combined['passed'] = passed | ||
| compiled_scenarios.append(combined) | ||
|
|
||
| # 4. Compile new run metadata | ||
| new_run = { | ||
| 'timestamp': datetime.datetime.now(datetime.timezone.utc).isoformat(), | ||
| 'commit_sha': os.environ.get('GITHUB_SHA', 'local-dev'), | ||
| 'github_run_id': os.environ.get('GITHUB_RUN_ID', '0'), | ||
| 'all_passed': all_passed, | ||
| 'scenarios': compiled_scenarios, | ||
| } | ||
|
|
||
| # 5. Merge and Prune rolling window | ||
| history.append(new_run) | ||
| history_limit = int( | ||
| os.environ.get('ITK_HISTORY_LIMIT', str(DEFAULT_HISTORY_LIMIT)) | ||
| ) | ||
| if len(history) > history_limit: | ||
| history = history[-history_limit:] | ||
| logger.info('Pruned history to last %d entries.', history_limit) | ||
|
|
||
| # 6. Save candidates back to disk | ||
| save_history(HISTORY_OUTPUT_FILE, history) | ||
| sys.exit(0) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| { | ||
| "tests": [ | ||
| { | ||
| "name": "Star Topology (Full) - JSONRPC & GRPC", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], | ||
| "protocols": ["jsonrpc", "grpc"], | ||
| "behavior": "send_message" | ||
| }, | ||
| { | ||
| "name": "Star Topology (No Go v03) - HTTP_JSON", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], | ||
| "protocols": ["http_json"], | ||
| "behavior": "send_message" | ||
| }, | ||
| { | ||
| "name": "Star Topology (Full) - JSONRPC & GRPC (Streaming)", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], | ||
| "protocols": ["jsonrpc", "grpc"], | ||
| "streaming": true, | ||
| "behavior": "send_message" | ||
| }, | ||
| { | ||
| "name": "Star Topology (No Go v03) - HTTP_JSON (Streaming)", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], | ||
| "protocols": ["http_json"], | ||
| "streaming": true, | ||
| "behavior": "send_message" | ||
| }, | ||
| { | ||
| "name": "Push Notification Test - JSONRPC & GRPC", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v03"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], | ||
| "protocols": ["jsonrpc", "grpc"], | ||
| "behavior": "push_notification" | ||
| }, | ||
| { | ||
| "name": "Push Notification Test - HTTP_JSON", | ||
| "sdks": ["current", "python_v10", "python_v03"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "1->0", "2->0"], | ||
| "protocols": ["http_json"], | ||
| "behavior": "push_notification" | ||
| }, | ||
| { | ||
| "name": "Resubscribe Test - JSONRPC", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10", "go_v03"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "0->4", "1->0", "2->0", "3->0", "4->0"], | ||
| "protocols": ["jsonrpc"], | ||
| "streaming": true, | ||
| "behavior": "resubscribe" | ||
| }, | ||
| { | ||
| "name": "Resubscribe Test - Python & Go Non-JSONRPC Protocols", | ||
| "sdks": ["current", "python_v10", "python_v03", "go_v10"], | ||
| "traversal": "euler", | ||
| "edges": ["0->1", "0->2", "0->3", "1->0", "2->0", "3->0"], | ||
| "protocols": ["grpc", "http_json"], | ||
| "streaming": true, | ||
| "behavior": "resubscribe" | ||
| } | ||
| ] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.