Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/check-binder-files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Test Binder Notebook Links

on:
push:
branches: [ main ]
paths:
- '.binder/files_to_fetch.txt'
pull_request:
types: [ opened, synchronize, reopened ]
branches: [ main ]
schedule:
# run every Monday at 08:00 UTC to catch broken links automatically
- cron: '0 8 * * 1'
workflow_dispatch: # allow manual triggering from the Actions tab

jobs:
test-notebook-links:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest

- name: Run notebook URL unit tests
run: |
pytest tests/test_binder_files.py -v
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
49 changes: 49 additions & 0 deletions tests/test_binder_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from pathlib import Path
import urllib.request
import urllib.error
import pytest

REPO_OWNER = "Parcels-code"
REPO_NAME = "virtualship"
BRANCH = "main"

# path to the list file relative to the repository root
LIST_FILE = Path(__file__).parent.parent / ".binder" / "files_to_fetch.txt"


def get_target_files():
"""Reads non-empty, non-comment lines from files_to_fetch.txt."""
if not LIST_FILE.exists():
pytest.fail(f"List file not found at: {LIST_FILE}")

files = []
with open(LIST_FILE, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"):
files.append(line)
return files


@pytest.mark.parametrize("file_path", get_target_files())
def test_remote_notebook_exists(file_path):
"""Sends a HEAD request to verify each notebook URL is active (HTTP 200)."""
raw_url = f"https://raw.githubusercontent.com/{REPO_OWNER}/{REPO_NAME}/{BRANCH}/{file_path}"

req = urllib.request.Request(raw_url, method="HEAD")

try:
with urllib.request.urlopen(req) as response:
assert response.status == 200, (
f"Expected status 200, got {response.status} for {raw_url}"
)
except urllib.error.HTTPError as e:
pytest.fail(
f"Failed to reach notebook at '{file_path}'.\n"
f"URL: {raw_url}\n"
f"HTTP Error: {e.code} {e.reason}\n"
f"Please update '.binder/files_to_fetch.txt' or report on the issue tracker: "
f"https://github.com/{REPO_OWNER}/{REPO_NAME}/issues"
)
except urllib.error.URLError as e:
pytest.fail(f"Network error while connecting to {raw_url}: {e.reason}")
Loading