diff --git a/.github/workflows/tutorial-automation.yml b/.github/workflows/tutorial-automation.yml index 28cdd940..f04906d4 100644 --- a/.github/workflows/tutorial-automation.yml +++ b/.github/workflows/tutorial-automation.yml @@ -136,16 +136,6 @@ jobs: oso/apps/docs/docs/tutorials/ rsync -a mdx_build/apps/docs/docs/tutorials/index.* \ oso/apps/docs/docs/tutorials/ - - - name: Format new tutorials with Prettier - run: | - NEW_FILES=$(find mdx_build/apps/docs/docs/tutorials \ - -type f \( -name '*.md' -o -name '*.mdx' \) \ - -printf '%P\n') - - for f in $NEW_FILES; do - npx prettier --write "oso/apps/docs/docs/tutorials/$f" - done - name: Create or update PR uses: peter-evans/create-pull-request@v5 diff --git a/.github/workflows/tutorial-checks.yml b/.github/workflows/tutorial-checks.yml new file mode 100644 index 00000000..84953ee9 --- /dev/null +++ b/.github/workflows/tutorial-checks.yml @@ -0,0 +1,92 @@ +name: Tutorial Checks +description: | + Runs checks on Jupyter notebooks in the tutorials/ directory: + - Ensures only .ipynb files are present + - Formats notebooks with Prettier + - Executes notebooks and fails on any errors +on: + pull_request: + paths: + - "tutorials/**" + +jobs: + check-notebooks: + runs-on: ubuntu-latest + + # list all files (in tutorials/) to ignore here + env: + IGNORED_FILES: | + tutorials/readme.md + steps: + - name: Check out PR branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect files added or modified in tutorials/ + id: filter + uses: dorny/paths-filter@v3 + with: + filters: | + notebooks: + - added|modified: "tutorials/**" + + - name: Enforce *.ipynb-only rule + if: steps.filter.outputs.notebooks == 'true' + run: | + # get everything under tutorials/ that changed + raw=$(git diff --name-only ${{github.event.pull_request.base.sha}} ${{github.sha}} -- tutorials/**/*.ipynb) + + # filter out any ignored files + bad=$(printf "%s\n" "$not_ipynb" | grep -vFf <(echo "$IGNORED_FILES") || true) + if [ -n "$bad" ]; then + echo "::error::The following files are not allowed in tutorials/:" + echo "$bad" + exit 1 + fi + + - name: Export notebook list + if: steps.filter.outputs.notebooks == 'true' + id: list + run: | + files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} -- tutorials/**/*.ipynb \ + | paste -sd ' ' -) + echo "files=$files" >> "$GITHUB_OUTPUT" + + - name: Set up Node & Prettier + if: steps.filter.outputs.notebooks == 'true' + uses: actions/setup-node@v4 + with: + node-version: '20' + + - run: npm install --global prettier + if: steps.filter.outputs.notebooks == 'true' + + - name: Prettier --check + if: steps.filter.outputs.notebooks == 'true' + run: | + prettier --check ${{ steps.list.outputs.files }} + + - name: Set up Python and Jupyter + if: steps.filter.outputs.notebooks == 'true' + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Jupyter tooling + kernel + if: steps.filter.outputs.notebooks == 'true' + run: | + pip install --quiet nbconvert ipykernel + python -m ipykernel install --name python3 --display-name "Python 3 (CI)" --user + + - name: Execute notebooks + if: steps.filter.outputs.notebooks == 'true' + run: | + for nb in ${{ steps.list.outputs.files }}; do + echo "Running $nb" + jupyter nbconvert --execute \ + --ExecutePreprocessor.kernel_name=python3 \ + --to notebook "$nb" \ + --output /tmp/out.ipynb + done + \ No newline at end of file diff --git a/tutorials/forecasting.ipynb b/tutorials/forecasting.ipynb index bba0cd17..fb2c56c4 100644 --- a/tutorials/forecasting.ipynb +++ b/tutorials/forecasting.ipynb @@ -1,19 +1,12 @@ { "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "[Open in Colab](https://colab.research.google.com/drive/1zEDIOioIyvj7dGCPch9C9c5eGrKX5BDQ)\n" - ] - }, { "cell_type": "markdown", "id": "ed162a68", "metadata": {}, "source": [ "## TVL Forecasting with PyOSO\n", - "*A quick-start notebook guide on working with pyoso*" + "*A quickstart notebook guide on working with pyoso*" ] }, { @@ -1345,4 +1338,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/tutorials/readme.md b/tutorials/readme.md index ba32fa2e..bf196515 100644 --- a/tutorials/readme.md +++ b/tutorials/readme.md @@ -1,9 +1,108 @@ -# Tutorials +# OSO Tutorials -Examples of applications and data science built on OSO's data platform. Each example is a notebook with you can fork and run yourself. +This folder contains runnable examples and data science tutorials built on OSO's data platform. +Each tutorial is a standalone Jupyter notebook (`.ipynb`) that can be viewed on Colab and is published to the OSO documentation site once approved. +--- +## How to Add a New Tutorial -For complete documentation and to run the notebooks see: https://docs.opensource.observer/docs/tutorials/ +Follow these steps to contribute your own tutorial to the platform: +### 1. Create & Upload Your Notebook + +- Write your tutorial as a Jupyter notebook (`.ipynb`) +- Save it to the `tutorials/` folder in the **`insights`** repository (where this file lives) + +### 2. Open a Pull Request + +- Open a PR with your new tutorial notebook +- Use the title prefix: **`NEW TUTORIAL:`** so we can easily identify it +- Your PR will run automated checks defined in `.github/workflows/tutorial-checks.yml`. These checks **must pass**: + - The file is a valid `.ipynb` + - The notebook is formatted using Prettier + - **Every cell in the notebook runs successfully** + +> ⚠️ **Make sure your tutorial is fully executable! CI will fail if any cell errors out.** + +### 3. Add Reviewers + +- Request review from [@evanameyer1](https://github.com/evanameyer1) or [@ccerv1](https://github.com/ccerv1) + +Once your tutorial is approved and merged, continue to the next step. + +--- + +## Publish Your Tutorial + +If you are happy with your tutorial solely exist in our insights repo then you do not need to run either of these workflows. These simply offer ways to build more coverage of your tutorial. + +We support two automation flows via `.github/workflows/tutorial-automation.yml`: + +### 1. Generate a Colab Notebook + +This creates a Colab link and inserts it into the notebook. + +```bash +gh workflow run "Tutorial Automation" \ + --ref main \ + -f command=colab \ + -f notebook="tutorials/your-notebook.ipynb" \ + -f sidebar_position=0 +```` + +* The Colab notebook will be auto-uploaded [here](https://drive.google.com/drive/u/2/folders/1ld_KWqNDMJl4NmzEFquNybCBph96hYDu) +* A line like `**[Open in Colab](https://...link...)**` will be added to the top of the notebook +* The changes are automatically committed and pushed to the same PR branch + +### 2. Generate Docs Page (MDX) + +This converts your notebook to a `.mdx` file for OSO's docs: + +```bash +gh workflow run "Tutorial Automation" \ + --ref main \ + -f command=docs \ + -f notebook="tutorials/your-notebook.ipynb" \ + -f sidebar_position=10 # See below on how to pick this +``` + +* A new MDX page is created for your tutorial at [https://docs.opensource.observer/docs/tutorials/](https://docs.opensource.observer/docs/tutorials/) +* The tutorials index (`index.mdx`) is updated with an LLM-generated title and description that matches our existing docs style +* A PR will be created on the **`oso`** repo titled `"Add MDX tutorial(s)"`, which must pass OSO’s CI + +--- + +## Sidebar Position Guide + +The `sidebar_position` parameter controls where your tutorial appears in the docs sidebar: + +* `0` = Top of the list (reserved for "Find a Tutorial") +* To **add your tutorial to the bottom**, find the bottommost tutorial in the docs sidebar: + + * Click **“Edit this page”** on the tutorial + * Look for its `sidebar_position` in the frontmatter + * Use that number +1 for your new tutorial + +> ⚠️ You **must** pass a `sidebar_position` even when running the `colab` workflow, but you can just use `0` there. + +--- + +## Tip: Quoting Names in GitHub CLI + +If you're using the workflow **name** instead of the workflow **ID**, wrap the name in quotes: + +```bash +gh workflow run "Tutorial Automation" ... +``` + +Or, run this to find the workflow ID (recommended): + +```bash +gh workflow list +``` + +--- + +Thanks for contributing to the OSO community! 🚀