chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:10:23 +08:00
commit fbab2c6005
567 changed files with 114434 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
name: 🐛 Bug Report
description: Report a bug or unexpected behavior (app is running but misbehaving)
title: "[Bug]: "
labels: ["bug", "needs-triage"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting a bug! Please fill out the information below to help us understand and fix the issue.
**Note**: If you're having installation or setup issues, please use the "Installation Issue" template instead.
- type: textarea
id: what-happened
attributes:
label: What did you do when it broke?
description: Describe the steps you took that led to the bug
placeholder: |
1. I went to the Notebooks page
2. I clicked on "Create New Notebook"
3. I filled in the form and clicked "Save"
4. Then the error occurred...
validations:
required: true
- type: textarea
id: how-broke
attributes:
label: How did it break?
description: What happened that was unexpected? What did you expect to happen instead?
placeholder: |
Expected: The notebook should be created and I should see it in the list
Actual: I got an error message saying "Failed to create notebook"
validations:
required: true
- type: textarea
id: logs-screenshots
attributes:
label: Logs or Screenshots
description: |
Please provide any error messages, logs, or screenshots that might help us understand the issue.
**How to get logs:**
- Docker: `docker compose logs -f open_notebook`
- Check browser console (F12 → Console tab)
placeholder: |
Paste logs here or drag and drop screenshots.
Error messages, stack traces, or browser console errors are very helpful!
validations:
required: false
- type: dropdown
id: version
attributes:
label: Open Notebook Version
description: Which version are you using?
options:
- v1-latest (Docker)
- v1-latest-single (Docker, deprecated)
- Latest from main branch
- Other (please specify in additional context)
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: What environment are you running in?
placeholder: |
- OS: Ubuntu 22.04 / Windows 11 / macOS 14
- Browser: Chrome 120
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other information that might be helpful
placeholder: "This started happening after I upgraded to v1.5.0..."
validations:
required: false
- type: checkboxes
id: willing-to-contribute
attributes:
label: Contribution
description: Would you like to work on fixing this bug?
options:
- label: I am a developer and would like to work on fixing this issue (pending maintainer approval)
required: false
- type: markdown
attributes:
value: |
---
**Next Steps:**
1. A maintainer will review your bug report
2. If you checked the box above and want to fix it, please propose your solution approach
3. Wait for assignment before starting development
4. See our [Contributing Guide](https://github.com/lfnovo/open-notebook/blob/main/CONTRIBUTING.md) for more details
+11
View File
@@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Discord Community
url: https://discord.gg/37XJPXfz2w
about: Get help from the community and share ideas
- name: 🤖 Installation Assistant (ChatGPT)
url: https://chatgpt.com/g/g-68776e2765b48191bd1bae3f30212631-open-notebook-installation-assistant
about: CustomGPT that knows all our docs. Really useful. Try it.
- name: 📚 Documentation
url: https://github.com/lfnovo/open-notebook/tree/main/docs
about: Browse our comprehensive documentation
@@ -0,0 +1,65 @@
name: ✨ Feature Suggestion
description: Suggest a new feature or improvement for Open Notebook
title: "[Feature]: "
labels: ["enhancement", "needs-triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to suggest a feature! Your ideas help make Open Notebook better for everyone.
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: What feature would you like to see added or improved?
placeholder: "I would like to be able to..."
validations:
required: true
- type: textarea
id: why-helpful
attributes:
label: Why would this be helpful?
description: Explain how this feature would benefit you and other users
placeholder: "This would help because..."
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution (Optional)
description: If you have ideas on how to implement this feature, please share them
placeholder: "This could be implemented by..."
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other context, screenshots, or examples that might be helpful
placeholder: "For example, other tools do this by..."
validations:
required: false
- type: checkboxes
id: willing-to-contribute
attributes:
label: Contribution
description: Would you like to work on implementing this feature?
options:
- label: I am a developer and would like to work on implementing this feature (pending maintainer approval)
required: false
- type: markdown
attributes:
value: |
---
**Next Steps:**
1. A maintainer will review your feature request
2. If approved and you checked the box above, the issue will be assigned to you
3. Please wait for assignment before starting development
4. See our [Contributing Guide](https://github.com/lfnovo/open-notebook/blob/main/CONTRIBUTING.md) for more details
@@ -0,0 +1,148 @@
name: 🔧 Installation Issue
description: Report problems with installation, setup, or connectivity
title: "[Install]: "
labels: ["installation", "needs-triage"]
body:
- type: markdown
attributes:
value: |
## ⚠️ Before You Continue
**Please try these resources first:**
1. 🤖 **[Installation Assistant ChatGPT](https://chatgpt.com/g/g-68776e2765b48191bd1bae3f30212631-open-notebook-installation-assistant)** - Our AI assistant can help you troubleshoot most installation issues instantly!
2. 📚 **[Installation Guide](https://github.com/lfnovo/open-notebook/blob/main/docs/getting-started/installation.md)** - Comprehensive setup instructions
3. 🐋 **[Docker Deployment Guide](https://github.com/lfnovo/open-notebook/blob/main/docs/deployment/docker.md)** - Detailed Docker setup
4. 🦙 **Ollama Issues?** Read our [Ollama Guide](https://github.com/lfnovo/open-notebook/blob/main/docs/features/ollama.md) first
5. 💬 **[Discord Community](https://discord.gg/37XJPXfz2w)** - Get real-time help from the community
---
If you've tried the above and still need help, please fill out the form below with as much detail as possible.
- type: dropdown
id: installation-method
attributes:
label: Installation Method
description: How are you trying to install Open Notebook?
options:
- Docker (docker-compose - recommended)
- Docker (single container - v1-latest-single, deprecated)
- Local development (make start-all)
- Other (please specify below)
validations:
required: true
- type: textarea
id: issue-description
attributes:
label: What is the issue?
description: Describe the installation or setup problem you're experiencing
placeholder: |
Example: "I can't connect to the database" or "The container won't start" or "Getting 404 errors when accessing the UI"
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs
description: |
Please provide relevant logs. **This is very important for diagnosing issues!**
**How to get logs:**
- Docker single container: `docker logs open-notebook`
- Docker Compose: `docker compose logs -f`
- Specific service: `docker compose logs -f open_notebook`
placeholder: |
Paste your logs here. Include the full error message and stack trace if available.
render: shell
validations:
required: false
- type: textarea
id: docker-compose
attributes:
label: Docker Compose Configuration
description: |
If using Docker Compose, please paste your `docker-compose.yml` file here.
**⚠️ IMPORTANT: Redact any sensitive information (API keys, passwords, etc.)**
placeholder: |
services:
open_notebook:
image: lfnovo/open_notebook:v1-latest-single
ports:
- "8502:8502"
- "5055:5055"
environment:
- OPENAI_API_KEY=sk-***REDACTED***
...
render: yaml
validations:
required: false
- type: textarea
id: env-file
attributes:
label: Environment File
description: |
If using an `.env` or `docker.env` file, please paste it here.
**⚠️ IMPORTANT: REDACT ALL API KEYS AND PASSWORDS!**
placeholder: |
SURREAL_URL=ws://surrealdb:8000/rpc
SURREAL_USER=root
SURREAL_PASSWORD=***REDACTED***
OPENAI_API_KEY=sk-***REDACTED***
ANTHROPIC_API_KEY=sk-ant-***REDACTED***
render: shell
validations:
required: false
- type: textarea
id: system-info
attributes:
label: System Information
description: Tell us about your setup
placeholder: |
- Operating System: Ubuntu 22.04 / Windows 11 / macOS 14
- Docker version: `docker --version`
- Docker Compose version: `docker compose version`
- Architecture: amd64 / arm64 (Apple Silicon)
- Available disk space: `df -h`
- Available memory: `free -h` (Linux) or Activity Monitor (Mac)
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Any other information that might be helpful
placeholder: |
- Are you behind a corporate proxy or firewall?
- Are you using a VPN?
- Have you made any custom modifications?
- Did this work before and suddenly break?
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm you've tried these steps
options:
- label: I tried the [Installation Assistant ChatGPT](https://chatgpt.com/g/g-68776e2765b48191bd1bae3f30212631-open-notebook-installation-assistant)
required: false
- label: I read the relevant documentation ([Installation Guide](https://github.com/lfnovo/open-notebook/blob/main/docs/getting-started/installation.md) or [Ollama Guide](https://github.com/lfnovo/open-notebook/blob/main/docs/features/ollama.md))
required: false
- label: I searched existing issues to see if this was already reported
required: true
- label: I redacted all sensitive information (API keys, passwords, etc.)
required: true
+174
View File
@@ -0,0 +1,174 @@
# Release Process
Open Notebook uses a flow-driven release process. Work moves from `ready`
issues into pull requests, pull requests merge to `main`, and maintainers cut a
version when the branch has enough validated change to ship.
This document covers both the **mechanics** (how to cut, build and publish) and
the **confidence process** (how we know a release is good before users get it).
It was redesigned during the v1.11.0 release ([ADR-005](../docs/7-DEVELOPMENT/decisions/ADR-005-release-confidence-process.md)).
## Release Model
- Patch releases ship backwards-compatible fixes.
- Minor releases ship backwards-compatible features and improvements.
- Major releases are planned with a milestone when they include breaking
changes or migrations that need user coordination.
- Use the `in-dev-build` label for changes available in development images and
`released` for shipped work. (The `released` label was recreated during
v1.12.0 — it had been dropped from the curated label taxonomy while this
document still required it. If a label this document references is missing,
recreate it rather than skipping the step.)
## Normal Flow
1. Triage issues into `ready` once the scope and design are clear.
2. Implement each change in a focused pull request linked to the approved issue.
3. Merge the pull request after review and required checks pass.
4. Let the development build publish the `v1-dev` image from `main`.
5. Cut a stable release when `main` has a coherent set of changes ready for
users — following the confidence process below.
## The Confidence Process
Releases keep getting bigger; ad-hoc verification does not scale. Before
cutting, run this sequence:
### 0. Changelog audit
Diff `git log <last-tag>..main` against the `[Unreleased]` section of the
CHANGELOG. Every merged PR must be represented (entries reference the issue
number when one exists, the PR number otherwise). The changelog is the input
for both the test plan and the release notes — close the gaps first, via PR.
### 1. Risk-based test matrix
Build a matrix from the actual release diff: each change → what it can break
and for whom → which bucket tests it. Pay special attention to
**"does the protection break legitimate use?"** for security changes (e.g. an
SSRF guard vs. self-hosted Ollama on localhost) and to anything a reverse
proxy, an upgrade, or a big upload would exercise.
Buckets:
- **A — automated, high confidence, run now**: full backend suite, frontend
lint/tests/production build, the smoke-e2e agent (full API happy path + UI
verification), targeted regression probes for the release's specific risks,
dependency audit.
- **B — automatable with investment**: decide per item whether to build the
muscle now (it compounds: the image gate below started as a bucket-B item)
or verify manually this once.
- **C — needs the release owner**: real provider credentials, real TTS podcast
generation, visual/UX judgment, and the final check of the pushed image.
### 2. The image gate — test the artifact, not the repo
A green suite on `main` is not a working image. Run:
```bash
make docker-build-local # builds <version> + local tags
make release-test TAG=<new> OLD_TAG=<previous>
```
This runs two scenarios against real containers (`scripts/release-test/`):
- **Fresh install**: empty DB → migrations on boot → in-image worker processes
a source → API/frontend/nginx-proxied checks.
- **Upgrade**: boot the *published* previous image, seed data, swap to the new
image on the same volume → migrations apply, data survives.
Caveat: `docker-build-local` tags with the current `pyproject.toml` version —
`docker pull` the genuine previous tag before the upgrade test so you are not
comparing the new build against itself.
### 3. Fix loop with a re-test policy
Findings become focused PRs through the normal review flow. After each merge:
the cheap suite always re-runs; smoke/image gates re-run only if the fix
touches what they cover; manual verification is not repeated unless the fix
touches what was manually verified. Pre-existing bugs found along the way that
are not release regressions become backlog issues instead of scope creep.
## Cutting A Stable Release
1. Confirm `main` is green and the confidence process above has run.
2. Open the **cut PR**: bump `pyproject.toml`, date the `[Unreleased]` section
as `[<version>] - <date>`.
3. After merge: `make tag`.
4. Build and push version images **via CI** (it holds the registry
credentials): trigger the *Build and Release* workflow with
`push_latest=false`. Local `make docker-push` also works but requires
`docker login` on both registries.
5. **Verify the pushed image** (bucket C, final gate): run it locally with
`make release-stack TAG=<version> [DUMP=<dev-data-dump>]` — a browsable,
isolated stack, optionally with a copy of real data — and walk the core
flows in the browser.
6. Publish the GitHub release. A non-prerelease publication triggers the
workflow again and pushes the `v1-latest` tags automatically.
7. Verify the `v1-latest` manifests on Docker Hub and GHCR (both arches, both
variants), and mark shipped issues with `released`.
## Communication
Release notes follow this structure (see v1.11.0 as the reference):
1. One-line verdict + upgrade recommendation.
2. Sections: Security, Features, Performance, Notable fixes.
3. **Behavior changes for self-hosters** — anything that can require a config
tweak on upgrade gets an explicit callout.
4. **Thanks** — credit every contributor by handle with what they shipped
(collect via `git log <last-tag>..<tag>` + `gh pr view` for handles), plus
the issue reporters collectively. Never skip this section.
Announce on Discord after `v1-latest` is live.
## Retro
Close every release by asking: what should improve in this process? Apply the
accepted improvements immediately — update this document, the scripts under
`scripts/release-test/`, and the decision log while the context is fresh.
## Docker Image Publishing (reference)
| Command | What it does | Updates latest? |
|---------|--------------|-----------------|
| `make docker-build-local` | Build for current platform only (tags `<version>` + `local`) | No registry push |
| CI *Build and Release* (`push_latest=false`) | Push version tags via CI credentials | ❌ No |
| GitHub release published (non-prerelease) | CI pushes version + `v1-latest` | ✅ Yes |
| `make docker-push` / `docker-push-latest` | Local equivalents (need `docker login`) | ❌ / ✅ |
| `make tag` | Create and push a git tag matching `pyproject.toml` | — |
- **Platforms:** `linux/amd64`, `linux/arm64`
- **Registries:** Docker Hub + GitHub Container Registry
- **Image variants:** regular + single-container (`-single`). Both are built
from the same `Dockerfile`: regular is the default/`runtime` target, single
is `--target single`
- **Version source:** `pyproject.toml`
- Build issues: `docker builder prune`, then `make docker-buildx-reset`
## Known Gotchas
- **RC stack on non-default ports needs `API_URL`** or the browser talks to
`host:5055` — on a dev machine that is the development API (data crossover).
`rc-stack.sh` sets it; remember this for any custom setup.
- **Containerized app + host services**: credentials pointing at local
services (Ollama, LM Studio) need `http://host.docker.internal:<port>`.
- **SurrealDB import**: `OVERWRITE` goes after the type keyword
(`DEFINE FIELD OVERWRITE …`), and the exporter can leak a log line into the
dump — `rc-stack.sh` handles both.
- **Multiple local SurrealDB instances**: check which one the dev `.env`
actually points at (`SURREAL_URL`) before exporting data.
- **Dev-machine ports may belong to other projects**: check who owns
3000/5055/8000 (`lsof -nP -iTCP:<port> -sTCP:LISTEN` + the process cwd)
before starting or killing anything. The frontend runs fine on an alternate
port for smoke testing (`PORT=3001 npm run dev`) — pass the URL to the
smoke agent.
- **Manual error-path checklist items must be validated against the code
first**: some "missing configuration" scenarios are deliberate fallbacks,
not errors (e.g. transformation and tools defaults fall back to the chat
default). Confirm the expected behavior in the provisioning code before
putting "should show an error" on the bucket-C checklist.
- **The test suite runs against the live dev database** when a developer
`.env` is loaded. During bucket A, snapshot record counts per table before
and after the suite (e.g. credentials count) — a diff means a test is
leaking writes (this caught 48 leaked `Test` credentials in v1.12.0).
+109
View File
@@ -0,0 +1,109 @@
## Description
<!-- Provide a clear and concise description of what this PR does -->
## Related Issue
<!-- Non-trivial PRs (features, architecture changes) must link an approved issue.
Small obvious fixes (typo, docs, tiny bug) don't need one — write "N/A (small fix)" below.
Sizeable change without an issue? Mark this PR as draft and create the issue first. -->
Fixes #<!-- issue number, or "N/A (small fix)" -->
## Type of Change
<!-- Mark the relevant option with an "x" -->
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Code refactoring (no functional changes)
- [ ] Performance improvement
- [ ] Test coverage improvement
## How Has This Been Tested?
<!-- Describe the tests you ran and/or how you verified your changes work -->
- [ ] Tested locally with Docker
- [ ] Tested locally with development setup
- [ ] Added new unit tests
- [ ] Existing tests pass (`uv run pytest`)
- [ ] Manual testing performed (describe below)
**Test Details:**
<!-- Describe your testing approach -->
## Design Alignment
<!-- This section helps ensure your PR aligns with our project vision -->
**Which design principles does this PR support?** (See [VISION.md](https://github.com/lfnovo/open-notebook/blob/main/VISION.md))
- [ ] Privacy First
- [ ] Simplicity Over Features
- [ ] API-First Architecture
- [ ] Multi-Provider Flexibility
- [ ] Extensibility Through Standards
- [ ] Async-First for Performance
**Explanation:**
<!-- Brief explanation of how your changes align with these principles -->
## Checklist
<!-- Mark completed items with an "x" -->
### Code Quality
- [ ] My code follows PEP 8 style guidelines (Python)
- [ ] My code follows TypeScript best practices (Frontend)
- [ ] I have added type hints to my code (Python)
- [ ] I have added JSDoc comments where appropriate (TypeScript)
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] My changes generate no new warnings or errors
### Testing
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I ran linting: `make ruff` or `ruff check . --fix`
- [ ] I ran type checking: `make lint` or `uv run python -m mypy .`
### Documentation
- [ ] I have updated the relevant documentation in `/docs` (if applicable)
- [ ] I have added/updated docstrings for new/modified functions
- [ ] I have updated the API documentation (if API changes were made)
- [ ] I have added comments to complex logic
### Database Changes
- [ ] I have created migration scripts for any database schema changes (in `/migrations`)
- [ ] Migration includes both up and down scripts
- [ ] Migration has been tested locally
### Breaking Changes
- [ ] This PR includes breaking changes
- [ ] I have documented the migration path for users
- [ ] I have updated MIGRATION.md (if applicable)
## Screenshots (if applicable)
<!-- Add screenshots for UI changes -->
## Additional Context
<!-- Add any other context about the PR here -->
## Pre-Submission Verification
Before submitting, please verify:
- [ ] I have read [CONTRIBUTING.md](https://github.com/lfnovo/open-notebook/blob/main/docs/7-DEVELOPMENT/contributing.md)
- [ ] I have read [VISION.md](https://github.com/lfnovo/open-notebook/blob/main/VISION.md)
- [ ] This PR addresses an approved issue assigned to me, **or** it's a small obvious fix (typo, docs, tiny bug) that doesn't need one — for anything bigger without an issue, mark this PR as draft and open the issue (triage takes 12 days)
- [ ] I have not included unrelated changes in this PR
- [ ] My PR title follows conventional commits format (e.g., "feat: add user authentication")
---
**Thank you for contributing to Open Notebook!** 🎉
+300
View File
@@ -0,0 +1,300 @@
name: Build and Release
on:
workflow_dispatch:
inputs:
push_latest:
description: 'Also push v1-latest tags'
required: true
default: false
type: boolean
release:
types: [published]
permissions:
contents: read
packages: write
env:
GHCR_IMAGE: ghcr.io/lfnovo/open-notebook
DOCKERHUB_IMAGE: lfnovo/open_notebook
jobs:
extract-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
has_dockerhub_secrets: ${{ steps.check.outputs.has_dockerhub_secrets }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"
- name: Check for Docker Hub credentials
id: check
env:
SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
SECRET_DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
if [[ -n ""$SECRET_DOCKER_USERNAME"" && -n ""$SECRET_DOCKER_PASSWORD"" ]]; then
echo "has_dockerhub_secrets=true" >> $GITHUB_OUTPUT
echo "Docker Hub credentials available"
else
echo "has_dockerhub_secrets=false" >> $GITHUB_OUTPUT
echo "Docker Hub credentials not available - will only push to GHCR"
fi
build-regular:
needs: extract-version
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
df -h
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: needs.extract-version.outputs.has_dockerhub_secrets == 'true'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-regular-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-regular-
- name: Prepare Docker tags for regular build
id: tags-regular
env:
ENV_GHCR_IMAGE: ${{ env.GHCR_IMAGE }}
GITHUB_EVENT_INPUTS_PUSH_LATEST: ${{ github.event.inputs.push_latest }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_RELEASE_PRERELEASE: ${{ github.event.release.prerelease }}
ENV_DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_IMAGE }}
run: |
TAGS=""$ENV_GHCR_IMAGE":${{ needs.extract-version.outputs.version }}"
# Determine if we should push latest tags
PUSH_LATEST=""$GITHUB_EVENT_INPUTS_PUSH_LATEST""
if [[ -z "$PUSH_LATEST" ]]; then
PUSH_LATEST="false"
fi
# Add GHCR latest tag if requested or for non-prerelease releases
if [[ "$PUSH_LATEST" == "true" ]] || [[ ""$GITHUB_EVENT_NAME"" == "release" && ""$GITHUB_EVENT_RELEASE_PRERELEASE"" != "true" ]]; then
TAGS="${TAGS},"$ENV_GHCR_IMAGE":v1-latest"
fi
# Add Docker Hub tags if credentials available
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
TAGS="${TAGS},"$ENV_DOCKERHUB_IMAGE":${{ needs.extract-version.outputs.version }}"
if [[ "$PUSH_LATEST" == "true" ]] || [[ ""$GITHUB_EVENT_NAME"" == "release" && ""$GITHUB_EVENT_RELEASE_PRERELEASE"" != "true" ]]; then
TAGS="${TAGS},"$ENV_DOCKERHUB_IMAGE":v1-latest"
fi
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
echo "Generated tags: ${TAGS}"
- name: Build and push regular image
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: runtime
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.tags-regular.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
build-single:
needs: extract-version
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
df -h
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: needs.extract-version.outputs.has_dockerhub_secrets == 'true'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.buildx-cache-single
key: ${{ runner.os }}-buildx-single-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-single-
- name: Prepare Docker tags for single build
id: tags-single
env:
ENV_GHCR_IMAGE: ${{ env.GHCR_IMAGE }}
GITHUB_EVENT_INPUTS_PUSH_LATEST: ${{ github.event.inputs.push_latest }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_RELEASE_PRERELEASE: ${{ github.event.release.prerelease }}
ENV_DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_IMAGE }}
run: |
TAGS=""$ENV_GHCR_IMAGE":${{ needs.extract-version.outputs.version }}-single"
# Determine if we should push latest tags
PUSH_LATEST=""$GITHUB_EVENT_INPUTS_PUSH_LATEST""
if [[ -z "$PUSH_LATEST" ]]; then
PUSH_LATEST="false"
fi
# Add GHCR latest tag if requested or for non-prerelease releases
if [[ "$PUSH_LATEST" == "true" ]] || [[ ""$GITHUB_EVENT_NAME"" == "release" && ""$GITHUB_EVENT_RELEASE_PRERELEASE"" != "true" ]]; then
TAGS="${TAGS},"$ENV_GHCR_IMAGE":v1-latest-single"
fi
# Add Docker Hub tags if credentials available
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
TAGS="${TAGS},"$ENV_DOCKERHUB_IMAGE":${{ needs.extract-version.outputs.version }}-single"
if [[ "$PUSH_LATEST" == "true" ]] || [[ ""$GITHUB_EVENT_NAME"" == "release" && ""$GITHUB_EVENT_RELEASE_PRERELEASE"" != "true" ]]; then
TAGS="${TAGS},"$ENV_DOCKERHUB_IMAGE":v1-latest-single"
fi
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
echo "Generated tags: ${TAGS}"
- name: Build and push single-container image
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: single
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.tags-single.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache-single
cache-to: type=local,dest=/tmp/.buildx-cache-single-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache-single
mv /tmp/.buildx-cache-single-new /tmp/.buildx-cache-single
summary:
needs: [extract-version, build-regular, build-single]
runs-on: ubuntu-latest
if: always()
steps:
- name: Build Summary
env:
GITHUB_EVENT_INPUTS_PUSH_LATEST_____FALSE_: ${{ github.event.inputs.push_latest || 'false' }}
ENV_GHCR_IMAGE: ${{ env.GHCR_IMAGE }}
ENV_DOCKERHUB_IMAGE: ${{ env.DOCKERHUB_IMAGE }}
GITHUB_EVENT_INPUTS_PUSH_LATEST: ${{ github.event.inputs.push_latest }}
run: |
echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ needs.extract-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Push v1-Latest:** "$GITHUB_EVENT_INPUTS_PUSH_LATEST_____FALSE_"" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Registries:" >> $GITHUB_STEP_SUMMARY
echo "✅ **GHCR:** \`"$ENV_GHCR_IMAGE"\`" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
echo "✅ **Docker Hub:** \`"$ENV_DOCKERHUB_IMAGE"\`" >> $GITHUB_STEP_SUMMARY
else
echo "⏭️ **Docker Hub:** Skipped (credentials not configured)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Images Built:" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.build-regular.result }}" == "success" ]]; then
echo "✅ **Regular (GHCR):** \`"$ENV_GHCR_IMAGE":${{ needs.extract-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
if [[ ""$GITHUB_EVENT_INPUTS_PUSH_LATEST"" == "true" ]]; then
echo "✅ **Regular v1-Latest (GHCR):** \`"$ENV_GHCR_IMAGE":v1-latest\`" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
echo "✅ **Regular (Docker Hub):** \`"$ENV_DOCKERHUB_IMAGE":${{ needs.extract-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
if [[ ""$GITHUB_EVENT_INPUTS_PUSH_LATEST"" == "true" ]]; then
echo "✅ **Regular v1-Latest (Docker Hub):** \`"$ENV_DOCKERHUB_IMAGE":v1-latest\`" >> $GITHUB_STEP_SUMMARY
fi
fi
elif [[ "${{ needs.build-regular.result }}" == "skipped" ]]; then
echo "⏭️ **Regular:** Skipped" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Regular:** Failed" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.build-single.result }}" == "success" ]]; then
echo "✅ **Single (GHCR):** \`"$ENV_GHCR_IMAGE":${{ needs.extract-version.outputs.version }}-single\`" >> $GITHUB_STEP_SUMMARY
if [[ ""$GITHUB_EVENT_INPUTS_PUSH_LATEST"" == "true" ]]; then
echo "✅ **Single v1-Latest (GHCR):** \`"$ENV_GHCR_IMAGE":v1-latest-single\`" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
echo "✅ **Single (Docker Hub):** \`"$ENV_DOCKERHUB_IMAGE":${{ needs.extract-version.outputs.version }}-single\`" >> $GITHUB_STEP_SUMMARY
if [[ ""$GITHUB_EVENT_INPUTS_PUSH_LATEST"" == "true" ]]; then
echo "✅ **Single v1-Latest (Docker Hub):** \`"$ENV_DOCKERHUB_IMAGE":v1-latest-single\`" >> $GITHUB_STEP_SUMMARY
fi
fi
elif [[ "${{ needs.build-single.result }}" == "skipped" ]]; then
echo "⏭️ **Single:** Skipped" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Single:** Failed" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Platforms:" >> $GITHUB_STEP_SUMMARY
echo "- linux/amd64" >> $GITHUB_STEP_SUMMARY
echo "- linux/arm64" >> $GITHUB_STEP_SUMMARY
+275
View File
@@ -0,0 +1,275 @@
name: Development Build
on:
pull_request:
branches: [ main ]
push:
branches: [ main ]
paths-ignore:
- '**.md'
- 'docs/**'
- 'notebooks/**'
- '.github/workflows/claude*.yml'
workflow_dispatch:
inputs:
platform:
description: 'Platform to build'
required: true
default: 'linux/amd64'
type: choice
options:
- linux/amd64
- linux/arm64
- linux/amd64,linux/arm64
permissions:
contents: read
packages: write
env:
GHCR_IMAGE: ghcr.io/lfnovo/open-notebook
DOCKERHUB_IMAGE: lfnovo/open_notebook
jobs:
extract-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
has_dockerhub_secrets: ${{ steps.check.outputs.has_dockerhub_secrets }}
is_push_to_main: ${{ steps.check.outputs.is_push_to_main }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"
- name: Check environment
id: check
env:
SECRET_DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
SECRET_DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
# Check for Docker Hub credentials
if [[ -n "$SECRET_DOCKER_USERNAME" && -n "$SECRET_DOCKER_PASSWORD" ]]; then
echo "has_dockerhub_secrets=true" >> $GITHUB_OUTPUT
echo "Docker Hub credentials available"
else
echo "has_dockerhub_secrets=false" >> $GITHUB_OUTPUT
echo "Docker Hub credentials not available"
fi
# Check if this is a push to main (not a PR)
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "is_push_to_main=true" >> $GITHUB_OUTPUT
echo "This is a push to main - will publish v1-dev tags"
else
echo "is_push_to_main=false" >> $GITHUB_OUTPUT
echo "This is a PR or manual run - test build only"
fi
build-regular:
needs: extract-version
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Free up disk space
if: needs.extract-version.outputs.is_push_to_main == 'true'
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
df -h
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GitHub Container Registry
if: needs.extract-version.outputs.is_push_to_main == 'true'
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: needs.extract-version.outputs.is_push_to_main == 'true' && needs.extract-version.outputs.has_dockerhub_secrets == 'true'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.buildx-cache-dev
key: ${{ runner.os }}-buildx-dev-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-dev-
- name: Prepare Docker tags
id: tags
run: |
if [[ "${{ needs.extract-version.outputs.is_push_to_main }}" == "true" ]]; then
# Push to main: build and push v1-dev tags
TAGS="${{ env.GHCR_IMAGE }}:v1-dev"
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
TAGS="${TAGS},${{ env.DOCKERHUB_IMAGE }}:v1-dev"
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
echo "push=true" >> $GITHUB_OUTPUT
echo "platforms=linux/amd64,linux/arm64" >> $GITHUB_OUTPUT
else
# PR or manual: test build only
echo "tags=${{ env.DOCKERHUB_IMAGE }}:${{ needs.extract-version.outputs.version }}-dev" >> $GITHUB_OUTPUT
echo "push=false" >> $GITHUB_OUTPUT
echo "platforms=${{ github.event.inputs.platform || 'linux/amd64' }}" >> $GITHUB_OUTPUT
fi
- name: Build and push regular image
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: runtime
platforms: ${{ steps.tags.outputs.platforms }}
push: ${{ steps.tags.outputs.push }}
tags: ${{ steps.tags.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache-dev
cache-to: type=local,dest=/tmp/.buildx-cache-dev-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache-dev
mv /tmp/.buildx-cache-dev-new /tmp/.buildx-cache-dev
build-single:
needs: extract-version
# Only build single image on push to main
if: needs.extract-version.outputs.is_push_to_main == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
df -h
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: needs.extract-version.outputs.has_dockerhub_secrets == 'true'
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Cache Docker layers
uses: actions/cache@v5
with:
path: /tmp/.buildx-cache-dev-single
key: ${{ runner.os }}-buildx-dev-single-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-dev-single-
- name: Prepare Docker tags
id: tags
run: |
TAGS="${{ env.GHCR_IMAGE }}:v1-dev-single"
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
TAGS="${TAGS},${{ env.DOCKERHUB_IMAGE }}:v1-dev-single"
fi
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Build and push single-container image
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: single
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.tags.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache-dev-single
cache-to: type=local,dest=/tmp/.buildx-cache-dev-single-new,mode=max
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache-dev-single
mv /tmp/.buildx-cache-dev-single-new /tmp/.buildx-cache-dev-single
summary:
needs: [extract-version, build-regular, build-single]
runs-on: ubuntu-latest
if: always()
steps:
- name: Development Build Summary
run: |
echo "## Development Build Summary" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ needs.extract-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Event:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "**Push to Main:** ${{ needs.extract-version.outputs.is_push_to_main }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.extract-version.outputs.is_push_to_main }}" == "true" ]]; then
echo "### Published Tags:" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.build-regular.result }}" == "success" ]]; then
echo "✅ **Regular:** \`${{ env.GHCR_IMAGE }}:v1-dev\`" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
echo "✅ **Regular (Docker Hub):** \`${{ env.DOCKERHUB_IMAGE }}:v1-dev\`" >> $GITHUB_STEP_SUMMARY
fi
else
echo "❌ **Regular:** Build failed" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.build-single.result }}" == "success" ]]; then
echo "✅ **Single:** \`${{ env.GHCR_IMAGE }}:v1-dev-single\`" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.extract-version.outputs.has_dockerhub_secrets }}" == "true" ]]; then
echo "✅ **Single (Docker Hub):** \`${{ env.DOCKERHUB_IMAGE }}:v1-dev-single\`" >> $GITHUB_STEP_SUMMARY
fi
elif [[ "${{ needs.build-single.result }}" == "skipped" ]]; then
echo "⏭️ **Single:** Skipped" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Single:** Build failed" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Platforms:" >> $GITHUB_STEP_SUMMARY
echo "- linux/amd64" >> $GITHUB_STEP_SUMMARY
echo "- linux/arm64" >> $GITHUB_STEP_SUMMARY
else
echo "### Test Build Results:" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.build-regular.result }}" == "success" ]]; then
echo "✅ **Dockerfile:** Build successful" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Dockerfile:** Build failed" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Notes:" >> $GITHUB_STEP_SUMMARY
echo "- This is a test build (no images pushed to registry)" >> $GITHUB_STEP_SUMMARY
echo "- Merge to main to publish \`v1-dev\` tags" >> $GITHUB_STEP_SUMMARY
echo "- For stable releases, use the 'Build and Release' workflow" >> $GITHUB_STEP_SUMMARY
fi
+16
View File
@@ -0,0 +1,16 @@
name: Docs Link Check
on:
pull_request:
paths:
- "**/*.md"
- "scripts/check_md_links.py"
- ".github/workflows/docs-links.yml"
jobs:
check-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check relative markdown links
run: python3 scripts/check_md_links.py
+159
View File
@@ -0,0 +1,159 @@
name: Tests
on:
pull_request:
branches: [main]
push:
branches: [main]
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/workflows/claude*.yml'
permissions:
contents: read
jobs:
backend:
name: Backend Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up uv
uses: astral-sh/setup-uv@v8.1.0
with:
enable-cache: true
- name: Set up Python
run: uv python install
- name: Install dependencies
run: uv sync
- name: Run tests with coverage
run: uv run pytest tests/ -v --cov=open_notebook --cov=api --cov-report=term-missing --cov-report=xml
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: backend-coverage
path: coverage.xml
backend-lint:
name: Backend Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up uv
uses: astral-sh/setup-uv@v8.1.0
with:
enable-cache: true
- name: Set up Python
run: uv python install
- name: Install dependencies
run: uv sync
- name: Run ruff
run: uv run ruff check .
backend-typecheck:
name: Backend Typecheck
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up uv
uses: astral-sh/setup-uv@v8.1.0
with:
enable-cache: true
- name: Set up Python
run: uv python install
- name: Install dependencies
run: uv sync
- name: Run mypy
run: uv run python -m mypy .
frontend:
name: Frontend Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run tests with coverage
run: npm run test:coverage
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: frontend-coverage
path: frontend/coverage/
frontend-lint:
name: Frontend Lint
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
frontend-build:
name: Frontend Build
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build