Skip to content

Commit 197cde2

Browse files
authored
Render notebooks for GitHub compatibility
Updated workflow to render Jupyter notebooks for GitHub compatibility, including handling VS Code format and adding widget state metadata.
1 parent 409444f commit 197cde2

1 file changed

Lines changed: 24 additions & 148 deletions

File tree

Lines changed: 24 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
name: Format Notebook for GitHub
1+
name: Render for GitHub
22

33
on:
4-
push:
5-
paths:
6-
- '**.ipynb'
74
pull_request:
85
branches:
96
- main
7+
push:
8+
paths:
9+
- '**.ipynb'
1010
workflow_dispatch: # Allows manual triggering
1111

1212
permissions:
1313
contents: write
1414
pull-requests: write
1515

1616
jobs:
17-
format-notebooks:
17+
render-notebooks:
1818
runs-on: ubuntu-latest
1919

2020
steps:
@@ -26,159 +26,35 @@ jobs:
2626
- name: Set up Python
2727
uses: actions/setup-python@v4
2828
with:
29-
python-version: '3.10'
29+
python-version: '3.x'
3030

3131
- name: Install dependencies
3232
run: |
3333
python -m pip install --upgrade pip
3434
pip install nbformat nbconvert jupyter
3535
36-
- name: Check and fix notebook format
37-
run: |
38-
# Create a script to fix notebooks
39-
cat > fix_notebooks.py << 'EOF'
40-
import os
41-
import json
42-
import nbformat
43-
from nbformat.validator import validate
44-
45-
# Find all notebook files
46-
notebook_files = []
47-
for root, dirs, files in os.walk('.'):
48-
if '.git' in dirs:
49-
dirs.remove('.git')
50-
for file in files:
51-
if file.endswith('.ipynb'):
52-
notebook_files.append(os.path.join(root, file))
53-
54-
print(f"Found {len(notebook_files)} notebooks to process")
55-
56-
# Process each notebook
57-
for nb_path in notebook_files:
58-
print(f"Processing {nb_path}")
59-
try:
60-
# Read the notebook
61-
with open(nb_path, 'r', encoding='utf-8') as f:
62-
content = f.read()
63-
64-
# Handle VS Code XML format
65-
if '<VSCode.Cell' in content:
66-
print(f" Converting from VS Code format...")
67-
# This is a simple conversion - in a real workflow you'd need more sophisticated parsing
68-
cells = []
69-
70-
# Extract markdown and code cells
71-
import re
72-
cell_pattern = re.compile(r'<VSCode.Cell.*?language="(.*?)".*?>(.*?)</VSCode.Cell>', re.DOTALL)
73-
for match in cell_pattern.finditer(content):
74-
cell_type, cell_content = match.groups()
75-
76-
if cell_type == "markdown":
77-
cells.append(nbformat.v4.new_markdown_cell(cell_content.strip()))
78-
elif cell_type in ["python", "javascript", "java", "typescript"]:
79-
cells.append(nbformat.v4.new_code_cell(cell_content.strip()))
80-
81-
# Create a new notebook
82-
nb = nbformat.v4.new_notebook()
83-
nb.cells = cells
84-
85-
# Add metadata
86-
nb.metadata = {
87-
"kernelspec": {
88-
"display_name": "Python 3",
89-
"language": "python",
90-
"name": "python3"
91-
},
92-
"language_info": {
93-
"codemirror_mode": {
94-
"name": "ipython",
95-
"version": 3
96-
},
97-
"file_extension": ".py",
98-
"mimetype": "text/x-python",
99-
"name": "python",
100-
"nbconvert_exporter": "python",
101-
"pygments_lexer": "ipython3",
102-
"version": "3.8.10"
103-
}
104-
}
105-
else:
106-
# Standard JSON format notebook
107-
nb = nbformat.reads(content, as_version=4)
108-
109-
# Ensure widget state exists if needed
110-
if "widgets" in str(content):
111-
print(f" Adding widget state metadata...")
112-
if "metadata" not in nb:
113-
nb["metadata"] = {}
114-
if "widgets" not in nb["metadata"]:
115-
nb.metadata["widgets"] = {
116-
"application/vnd.jupyter.widget-state+json": {
117-
"state": {},
118-
"version_major": 2,
119-
"version_minor": 0
120-
}
121-
}
122-
123-
# Validate the notebook
124-
validate(nb)
125-
126-
# Write the fixed notebook
127-
with open(nb_path, 'w', encoding='utf-8') as f:
128-
nbformat.write(nb, f)
129-
130-
print(f" Successfully processed {nb_path}")
131-
132-
except Exception as e:
133-
print(f" Error processing {nb_path}: {str(e)}")
134-
continue
135-
EOF
136-
137-
# Run the notebook fixing script
138-
python fix_notebooks.py
139-
140-
- name: Configure Git
36+
- name: Configure Git
14137
run: |
142-
git config --global user.name "github-actions[bot]"
14338
git config --global user.email "github-actions[bot]@users.noreply.github.com"
39+
git config --global user.name "github-actions[bot]"
14440
145-
- name: Commit changes (if any)
146-
run: |
147-
git add "*.ipynb"
148-
git commit -m "Fix notebook format for GitHub compatibility" || echo "No changes to commit"
149-
150-
- name: Push changes (PR)
151-
if: github.event_name == 'pull_request'
152-
env:
153-
TOKEN: ${{ secrets.GITHUB_TOKEN }}
154-
run: |
155-
git fetch origin
156-
git checkout -b ${{ github.event.pull_request.head.ref }} origin/${{ github.event.pull_request.head.ref }}
157-
git pull --rebase origin ${{ github.event.pull_request.head.ref }} || echo "No rebase needed"
158-
git push origin HEAD:${{ github.event.pull_request.head.ref }}
41+
- name: Render notebooks for GitHub
42+
run: python .github/workflows/render_notebooks.py
15943

160-
- name: Push changes (non-PR)
161-
if: github.event_name != 'pull_request'
44+
- name: Commit changes
16245
env:
16346
TOKEN: ${{ secrets.GITHUB_TOKEN }}
16447
run: |
165-
git remote set-url origin https://x-access-token:${TOKEN}@github.com/${{ github.repository }}
166-
git push || echo "No changes to push"
167-
168-
- name: Create Pull Request (non-PR)
169-
if: github.event_name != 'pull_request'
170-
uses: peter-evans/create-pull-request@v6
171-
with:
172-
token: ${{ secrets.GITHUB_TOKEN }}
173-
branch: fix-notebook-format
174-
title: "Fix notebook format for GitHub compatibility"
175-
body: |
176-
This PR fixes Jupyter notebook formatting issues to ensure proper rendering on GitHub.
177-
178-
The workflow addresses:
179-
- Converting VS Code XML format to standard Jupyter JSON format
180-
- Adding missing widget state metadata
181-
- Ensuring notebook format complies with GitHub's requirements
182-
183-
These changes allow notebooks to render properly in GitHub's notebook viewer.
184-
base: main
48+
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
49+
git fetch origin ${{ github.event.pull_request.head.ref }}
50+
git pull --rebase origin ${{ github.event.pull_request.head.ref }} || echo "No rebase needed"
51+
git add "**/*.ipynb"
52+
git commit -m "Render notebooks for GitHub compatibility" || echo "No changes to commit"
53+
git remote set-url origin https://x-access-token:${TOKEN}@github.com/${{ github.repository }}
54+
git push origin HEAD:${{ github.event.pull_request.head.ref }}
55+
else
56+
git add "**/*.ipynb"
57+
git commit -m "Render notebooks for GitHub compatibility" || echo "No changes to commit"
58+
git remote set-url origin https://x-access-token:${TOKEN}@github.com/${{ github.repository }}
59+
git push origin ${{ github.ref_name }}
60+
fi

0 commit comments

Comments
 (0)