Skip to content
Draft
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
19 changes: 19 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[flake8]
# Ignore Jupyter notebook files
exclude =
.git,
__pycache__,
.ipynb_checkpoints,
*.ipynb,
build,
dist,
site,
gh-pages

# Maximum line length
max-line-length = 100

# Ignore specific error codes if needed
# E501: line too long (handled by max-line-length)
# W503: line break before binary operator (not a real issue)
ignore = W503
36 changes: 0 additions & 36 deletions .github/workflows/blank.yml

This file was deleted.

53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Lint (flake8)
run: |
flake8 .

- name: Run unit tests (pytest)
run: |
pytest -q --maxfail=1

- name: Execute all notebooks (nbconvert)
run: |
python - <<'PY'
import glob, subprocess, sys
notebooks = glob.glob('**/*.ipynb', recursive=True)
if not notebooks:
print("No notebooks found.")
sys.exit(0)
for n in notebooks:
print("Executing", n)
subprocess.check_call([
sys.executable, "-m", "jupyter", "nbconvert",
"--to", "notebook", "--execute", "--inplace",
"--ExecutePreprocessor.timeout=600", n
])
PY
90 changes: 90 additions & 0 deletions .github/workflows/deploy-notebooks-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
on:
push:
branches:
- '**'

name: Build and deploy notebooks to GitHub Pages (per-branch)

jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: write # needed to push gh-pages
steps:
- name: Checkout repository (current branch)
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Determine branch name
id: branch
run: |
echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" > $GITHUB_ENV
echo "branch=${GITHUB_REF#refs/heads/}" > $GITHUB_OUTPUT

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; else pip install jupyter nbconvert nbformat; fi

- name: Build notebooks to HTML for this branch
run: |
mkdir -p site/${{ env.BRANCH_NAME }}
python scripts/build_notebooks.py site/${{ env.BRANCH_NAME }}

- name: Prepare gh-pages branch workspace
run: |
# If gh-pages exists, clone it, otherwise init an empty gh-pages branch
REPO_URL="https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
if git ls-remote --exit-code origin gh-pages; then
git clone --depth 1 --branch gh-pages "$REPO_URL" gh-pages || git clone --single-branch --branch gh-pages "$REPO_URL" gh-pages
else
# create temporary folder, init gh-pages and push
mkdir gh-pages
cd gh-pages
git init
git remote add origin "$REPO_URL"
git checkout -b gh-pages || true
touch .nojekyll
git add .nojekyll
git commit -m "Initialize gh-pages"
git push origin gh-pages
cd ..
git clone --depth 1 --branch gh-pages "$REPO_URL" gh-pages
fi

- name: Copy built site into gh-pages under branch folder
run: |
set -e
rsync -a --delete site/${{ env.BRANCH_NAME }}/ gh-pages/${{ env.BRANCH_NAME }}/
# ensure a top-level index exists listing branches (optional)
python3 - <<'PY'
import os, json
root='gh-pages'
items = sorted([d for d in os.listdir(root) if os.path.isdir(os.path.join(root,d))])
index_path = os.path.join(root, 'index.html')
with open(index_path, 'w') as f:
f.write("<html><head><title>Published Branches</title></head><body>")
f.write("<h1>Published branches</h1><ul>")
for d in items:
f.write(f'<li><a href="{d}/">{d}</a></li>')
f.write("</ul></body></html>")
PY

- name: Commit and push changes to gh-pages
working-directory: gh-pages
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add --all
if git diff --quiet --cached; then
echo "No changes to deploy"
else
git commit -m "Deploy notebooks for branch '${{ env.BRANCH_NAME }}' [ci skip]"
git push origin gh-pages
fi
50 changes: 50 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Jupyter Notebook
.ipynb_checkpoints

# Testing
.pytest_cache/
.coverage
htmlcov/

# Build outputs
site/
gh-pages/

# Virtual environments
venv/
ENV/
env/
.venv

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
82 changes: 82 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Contributing

## CI/CD Workflows

This repository includes automated workflows for building, testing, and deploying Jupyter notebooks.

### CI Workflow (`.github/workflows/ci.yml`)

The CI workflow runs on every push and pull request to the `main` branch. It:

1. **Lints** the code using `flake8` to ensure code quality
2. **Runs unit tests** using `pytest` to validate functionality
3. **Executes all notebooks** to ensure they run without errors

To run these checks locally before pushing:

```bash
# Install dependencies
pip install -r requirements.txt

# Run linting
flake8 .

# Run tests
pytest -q --maxfail=1

# Execute notebooks
python scripts/build_notebooks.py /tmp/test-output
```

### Notebook Deployment Workflow (`.github/workflows/deploy-notebooks-pages.yml`)

The deployment workflow runs on every push to **any branch** and:

1. Executes all notebooks in the repository
2. Converts them to HTML
3. Publishes them to GitHub Pages under a branch-specific folder

The deployed notebooks are available at:
- `https://<username>.github.io/<repo>/<branch>/` for branch-specific builds
- `https://<username>.github.io/<repo>/` for an index of all published branches

### Building Notebooks Locally

To build notebooks locally for testing:

```bash
# Install dependencies
pip install -r requirements.txt

# Build notebooks to HTML
python scripts/build_notebooks.py output/

# View the generated HTML
open output/index.html # macOS
xdg-open output/index.html # Linux
```

### Adding New Notebooks

1. Create your `.ipynb` notebook file anywhere in the repository
2. Commit and push to your branch
3. The CI workflow will validate that the notebook executes successfully
4. The deployment workflow will automatically build and publish the notebook to GitHub Pages

### Troubleshooting

#### Notebook Execution Timeout

If a notebook takes longer than 600 seconds (10 minutes) to execute, you may need to:
- Optimize the notebook code
- Split it into smaller notebooks
- Increase the timeout in the workflow files

#### Flake8 Linting Errors

If you have Python code in the repository (not in notebooks), ensure it follows PEP 8 style guidelines:
- Maximum line length: 79 characters (default)
- Proper indentation and spacing
- No unused imports

To ignore certain flake8 errors, create a `.flake8` configuration file.
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Core Jupyter dependencies
jupyter>=1.0.0
nbconvert>=7.0.0
nbformat>=5.0.0

# Testing and linting
pytest>=7.0.0
flake8>=6.0.0
Loading
Loading