Skip to content

Latest commit

 

History

History
198 lines (125 loc) · 10 KB

File metadata and controls

198 lines (125 loc) · 10 KB

Contributing to JupyterLab Desktop

Thanks for your interest in contributing. This document covers building, running, testing and packaging the application. Elsewhere:

JupyterLab Desktop packages JupyterLab as an Electron application. A change to the notebook interface itself belongs in that repository; this one covers the desktop shell, the bundled Python environment and the installers.

Pull requests follow the template, which includes a section on AI usage. Answer both of its questions honestly, and keep the pull request in draft until you have run the code yourself.

This project follows the Jupyter Code of Conduct. Security vulnerabilities never go to a public issue: the Jupyter security policy asks for a GitHub Security Advisory on this repository, and security@jupyter.org only when that is not possible.

Build dependencies

  • conda

    You can install conda as part of a Miniforge installer.

  • conda pack and conda lock to bundle JupyterLab Desktop Server into the standalone application and to create lock files. You can install them using:

    conda install -c conda-forge conda-pack conda-lock
  • nodejs

    You can install from https://nodejs.org/en/download/ or run:

    conda install -c conda-forge nodejs
  • yarn

    Install using

    npm install --global yarn

Local development

JupyterLab Desktop bundles JupyterLab front-end and a conda environment as JupyterLab Desktop Server as its backend into an Electron application.

<platform>: osx-64, osx-arm64, linux-64, linux-aarch64 or win-64. The dist scripts also take osx, for both macOS architectures at once. package.json is the list. dist:win-arm64 exists but passes no --win, unlike every sibling, so on a non-Windows host it builds for the host platform instead and says nothing.

  • Get the project source code

    git clone https://github.com/jupyterlab/jupyterlab-desktop.git
  • Install dependencies and build JupyterLab Desktop

    yarn
    yarn build
  • Create the JupyterLab Desktop Server installer using

    yarn create_env_installer:<platform>

    Installer will be created in env_installer/jlab_server.tar.gz and will be available for use in env_installer/jlab_server.

  • Now you can launch the JupyterLab Desktop locally using:

    yarn start

    If JupyterLab Desktop does not find a compatible Python environment configured, it will prompt for installation using JupyterLab Desktop Server installer or let you choose a custom environment on your computer at first launch.

Testing

Unit tests are Vitest and live in test/unit. End-to-end tests are Playwright driving the real Electron app and live in test/e2e.

yarn test:unit         # vitest run
yarn test:unit:watch   # vitest, re-runs on change
yarn test:coverage     # vitest run --coverage, enforces the thresholds below
yarn test:e2e          # playwright test, requires yarn build first

yarn test:e2e launches the built entry point rather than the sources: package.json points main at ./build/out/main/main.js, and the tests call electron.launch against the project directory. On a clean checkout the run fails on a missing bundle rather than on a real defect, so run yarn build before it.

It also needs a Python with JupyterLab, pointed at by JLAB_TEST_PYTHON_PATH. Without it the env-backed specs skip rather than fail, so the suite reports green while the tests that exercise environments never ran. .github/workflows/e2e.yml builds a venv for this, and the same thing locally is:

python3 -m venv /tmp/jlab-venv
# the same pin the app bundles, which is what CI installs
ver=$(awk '$1=="-" && $2=="jupyterlab" {print $3}' env_installer/jlab_server.yaml)
/tmp/jlab-venv/bin/pip install "jupyterlab==$ver" ipywidgets
export JLAB_TEST_PYTHON_PATH=/tmp/jlab-venv/bin/python

Installing an unpinned JupyterLab works until it drifts from the bundled one, at which point the failure is version skew that CI cannot reproduce.

On Linux, Playwright needs its system libraries, and the app needs a display: npx playwright install-deps, then run the suite under xvfb-run -a. The app opens several windows, so a real display beats headless. macOS runners have one already.

Coverage is configured in vitest.config.ts with an explicit include list, which is what makes untested branches in those files count against the thresholds even when no test imports them: Vitest instruments every file the list matches, not only the ones a test reached. The list is scoped to the main-process logic modules, and leaves out the window, view, dialog and preload surfaces so that code a unit test cannot reach without a running Electron process does not dilute the denominator. Being outside the list is not the same as being untested: test/unit/preload alone holds twelve specs, and several of those surfaces have unit tests of their own. It only means no coverage floor is enforced on them. Besides the aggregate floor, several well-covered modules are locked at their current level so a later change cannot silently regress them.

The unit suite runs in CI as well: publish.yml runs yarn test:coverage on Linux, where the thresholds are enforced, and yarn test:unit on macOS and Windows, and its publish job is needs: test. A regressed threshold turns up there rather than here if you skip it.

Three more checks run in CI and are worth running before pushing:

yarn type-check           # tsc --noEmit, run by typecheck.yml
yarn lint:check           # prettier --check and eslint, no writes, run by publish.yml
yarn check_version_match  # desktop against bundled JupyterLab version, run by publish.yml

yarn lint is the same two with fixes applied, and CI never runs it, since a job that rewrites the tree would have nowhere to put the result. It also starts with a bare yarn, so it reinstalls dependencies and can rewrite yarn.lock; lint:check does not.

Prettier is pinned in devDependencies and its config is .prettierrc. The trap is the config rather than the binary: run against a file outside the project tree, prettier finds no .prettierrc to inherit, falls back to its defaults and reports wrapping differences that do not exist. Pass the config explicitly when checking anything that is not in place: ./node_modules/.bin/prettier --config ./.prettierrc --check <file>.

Building for distribution

  • Build the application

    yarn run clean && yarn build
  • Create JupyterLab Desktop Server installer

    yarn create_env_installer:<platform>
  • Create JupyterLab Desktop installer which will also bundle JupyterLab Desktop Server installer.

    yarn dist:<platform>

    Application Installer will be created in dist/JupyterLab-arm64.dmg or dist/JupyterLab-x64.dmg (macOS, which names the architecture), dist/JupyterLab.deb (Debian, Ubuntu), dist/JupyterLab.rpm (Red Hat, Fedora) and dist/JupyterLab-Setup.exe (Windows) based on the platform

Shared seams in the main process

These questions already have one answer, so please do not write a second one:

Question Where it is answered
What origin is this URL? originOf, isSameServerOrigin in src/main/utils.ts
Is this a scheme I accept? matchesScheme in src/main/utils.ts
May this surface navigate there? guardNavigation in src/main/navigationguard.ts, navigationpolicy.ts
Should this link leave the app? openUrlInSystemBrowser in src/main/navigationguard.ts

A webContents nobody claims cannot navigate at all, so a new view is safe until markGuarded opts it into a policy of its own.

Review guidance

Expected manual testing coverage depends on the PR, when pulling:

  • patch releases of JupyterLab or Electron: Testing on a single OS is sufficient.
  • minor or major JupyterLab releases and minor Electron releases: Test on multiple OSes.
  • major Electron releases: Test on all OSes.

A release PR must be approved by at least two people.

Key Checks

Depending on the PR, different part of the application may require testing. Use the guide below, but exercise your own judgment to skip or add more checks depending on circumstances.

For patch dependency update PRs:

  • Notebooks UI launches (smoke test, no extensive testing required)

For minor and major JupyterLab update PRs:

  • JupyterLab Desktop theme switching works
  • UI Mode switching works

For conda update PRs:

  • Creating new environments from "Manage Python Environments" dialog works
  • The environment picker popover shows up with a list of environments
  • Switching environments works

For minor and major Electron updates PR:

  • All checks listed above
  • No new errors in log files (e.g. ~/Library/Logs/jupyterlab-desktop/main.log) and when launching from terminal with jlab
  • The welcome screen opens, displays the news feed, recent sessions, and allows to create new sessions
  • The settings window opens

Before JupyterLab Desktop release:

  • All checks listed above

Release Instructions

For instructions on updating bundled JupyterLab packages and cutting a new release, please follow Release.md document.