Skip to content

Commit d61f6b4

Browse files
chore: merge main to update branch
2 parents 56e855d + 973dff7 commit d61f6b4

File tree

14 files changed

+293
-56
lines changed

14 files changed

+293
-56
lines changed

.codecov.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
coverage:
2+
status:
3+
project:
4+
default:
5+
target: auto
6+
threshold: 0.05%
7+
patch:
8+
default:
9+
target: auto
10+
threshold: 0.05%

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Default owners for everything in the repository
2+
* @saltenasl @jamesbhobbs @Artmann @andyjakubowski

.github/workflows/build.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ jobs:
4444
set -eux
4545
python -m pip install .[test]
4646
47-
pytest -vv -r ap --cov jupyterlab_deepnote
47+
mkdir -p coverage
48+
pytest -vv -r ap --cov jupyterlab_deepnote --cov-report=xml --junit-xml=coverage/pytest-results.xml
4849
jupyter server extension list
4950
jupyter server extension list 2>&1 | grep -ie "jupyterlab_deepnote.*OK"
5051
@@ -54,6 +55,21 @@ jobs:
5455
env:
5556
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5657

58+
- name: Upload coverage to Codecov
59+
uses: codecov/codecov-action@v5
60+
with:
61+
token: ${{ secrets.CODECOV_TOKEN }}
62+
files: coverage.xml,coverage/lcov.info
63+
fail_ci_if_error: true
64+
65+
- name: Upload test results to Codecov
66+
if: '!cancelled()'
67+
uses: codecov/test-results-action@v1
68+
with:
69+
token: ${{ secrets.CODECOV_TOKEN }}
70+
files: coverage/pytest-results.xml,coverage/junit.xml
71+
fail_ci_if_error: true
72+
5773
- name: Package the extension
5874
run: |
5975
set -eux
@@ -169,3 +185,5 @@ jobs:
169185
- uses: actions/checkout@v4
170186
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
171187
- uses: jupyterlab/maintainer-tools/.github/actions/check-links@v1
188+
with:
189+
ignore_links: 'https://github.com/deepnote/jupyterlab-deepnote/pull/ https://github.com/deepnote/jupyterlab-deepnote/issues/'

.github/workflows/check-licenses.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
12+
13+
permissions:
14+
contents: read
15+
pull-requests: read
16+
packages: read
17+
18+
jobs:
19+
qlty:
20+
name: Qlty Check
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 3
23+
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
27+
28+
- name: Install qlty
29+
uses: qltysh/qlty-action/install@06730ef41b86b073c3813c0fc07a0c734980ce5d
30+
31+
- name: Run qlty check
32+
run: qlty check
33+
34+
- name: Run qlty code smells analysis
35+
run: qlty smells
36+
37+
audit-prod:
38+
name: Audit - Production
39+
runs-on: ubuntu-latest
40+
timeout-minutes: 15
41+
steps:
42+
- name: Checkout
43+
uses: actions/checkout@v4
44+
45+
- name: Base Setup
46+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
47+
48+
- name: Install dependencies
49+
run: python -m pip install -U "jupyterlab>=4.0.0,<5"
50+
51+
- name: Install node dependencies
52+
run: jlpm
53+
env:
54+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55+
56+
- name: Run audit for production dependencies
57+
run: jlpm npm audit --environment production
58+
env:
59+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60+
61+
audit-all:
62+
name: Audit - All
63+
runs-on: ubuntu-latest
64+
timeout-minutes: 15
65+
steps:
66+
- name: Checkout
67+
uses: actions/checkout@v4
68+
69+
- name: Base Setup
70+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
71+
72+
- name: Install dependencies
73+
run: python -m pip install -U "jupyterlab>=4.0.0,<5"
74+
75+
- name: Install node dependencies
76+
run: jlpm
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
80+
- name: Run audit for all dependencies
81+
run: jlpm npm audit
82+
env:
83+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84+
85+
license-check:
86+
name: License Check
87+
runs-on: ubuntu-latest
88+
steps:
89+
- name: Checkout
90+
uses: actions/checkout@v4
91+
- name: Base Setup
92+
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
93+
94+
- name: Check licenses
95+
run: yarn check-licenses

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,9 @@ dmypy.json
123123

124124
# Yarn cache
125125
.yarn/
126+
# Qlty cache directories
127+
.qlty/cache
128+
.qlty/logs
129+
.qlty/out
130+
.qlty/plugin_cachedir
131+
.qlty/results

.qlty/qlty.toml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Qlty Configuration
2+
# Learn more at https://docs.qlty.sh
3+
config_version = "0"
4+
5+
# Plugins configuration
6+
[[plugin]]
7+
name = "actionlint"
8+
9+
[[plugin]]
10+
name = "trufflehog"
11+
12+
[[plugin]]
13+
name = "osv-scanner"
14+
15+
# Source configuration
16+
[[source]]
17+
name = "default"
18+
default = true
19+
20+
# Exclusion patterns
21+
exclude_patterns = [
22+
"node_modules/**",
23+
"dist/**",
24+
"build/**",
25+
"coverage/**",
26+
"**/*.min.js",
27+
"**/*.min.css",
28+
".git/**",
29+
".venv/**",
30+
"venv/**",
31+
".tox/**",
32+
".mypy_cache/**",
33+
"**/__pycache__/**",
34+
]
35+
36+
# Code Smells Configuration
37+
[smells]
38+
mode = "block"
39+
40+
[smells.boolean_logic]
41+
enabled = true
42+
threshold = 4
43+
44+
[smells.nested_control_flow]
45+
enabled = true
46+
threshold = 4
47+
48+
[smells.function_parameters]
49+
enabled = true
50+
threshold = 5
51+
52+
[smells.function_length]
53+
enabled = true
54+
threshold = 50
55+
56+
[smells.file_length]
57+
enabled = true
58+
threshold = 500
59+
60+
[smells.cognitive_complexity]
61+
enabled = true
62+
threshold = 15
63+
64+
[smells.duplicate_code]
65+
enabled = true
66+
threshold = 6
67+
68+
[smells.large_class]
69+
enabled = true
70+
threshold = 500
71+
72+
[smells.long_parameter_list]
73+
enabled = true
74+
threshold = 2

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ The `@deepnote/blocks` package is published on GitHub Packages. To install it, y
8282
- Select the `read:packages` scope
8383
- Generate and copy the token
8484

85-
2. Set the `GITHUB_TOKEN` environment variable to ensure `jlpm` (which is a wrapper around Yarn) can download the `@deepnote/blocks` package from the GitHub package registry. You can set the variable in `.zshrc` or manually like:
85+
2. Set the `GITHUB_TOKEN` environment variable to ensure `jlpm` (which is a wrapper around Yarn) can download the `@deepnote/blocks` package from the GitHub package registry. You can export the variable in `.zshrc` (or by reading a `~/.env` file):
8686
```shell
8787
export GITHUB_TOKEN=your_token_here
8888
```

jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ module.exports = {
2222
'!src/**/*.d.ts',
2323
'!src/**/.ipynb_checkpoints/*'
2424
],
25+
coverageDirectory: './coverage',
2526
coverageReporters: ['lcov', 'text'],
27+
reporters: [
28+
'default',
29+
['jest-junit', { outputDirectory: './coverage', outputName: 'junit.xml' }]
30+
],
2631
testRegex: 'src/.*/.*.spec.ts[x]?$',
2732
transformIgnorePatterns: [`/node_modules/(?!${esModules}).+`]
2833
};

src/components/NotebookPicker.tsx

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import { ReactWidget } from '@jupyterlab/apputils';
33
import { NotebookPanel } from '@jupyterlab/notebook';
44
import { HTMLSelect } from '@jupyterlab/ui-components';
5+
import { deepnoteMetadataSchema } from '../types';
56

67
export class NotebookPicker extends ReactWidget {
78
private selected: string | null = null;
@@ -31,22 +32,30 @@ export class NotebookPicker extends ReactWidget {
3132

3233
const selected = event.target.value;
3334
const deepnoteMetadata = this.panel.context.model.getMetadata('deepnote');
34-
const notebooks = deepnoteMetadata?.notebooks;
35+
const deepnoteMetadataValidated =
36+
deepnoteMetadataSchema.safeParse(deepnoteMetadata);
3537

36-
if (notebooks && selected in notebooks) {
37-
// clone the notebook JSON
38-
const newModelData = { ...notebooks[selected] };
38+
if (!deepnoteMetadataValidated.success) {
39+
console.error(
40+
'Invalid deepnote metadata:',
41+
deepnoteMetadataValidated.error
42+
);
43+
return;
44+
}
3945

40-
// preserve deepnote metadata *without* re-inserting all notebooks
41-
newModelData.metadata = {
42-
...(newModelData.metadata ?? {}),
43-
deepnote: {
44-
notebook_names: deepnoteMetadata?.notebook_names ?? [],
45-
notebooks: deepnoteMetadata?.notebooks ?? {}
46-
}
47-
};
46+
const notebooks = deepnoteMetadataValidated.data.notebooks;
4847

49-
model.fromJSON(newModelData);
48+
if (selected in notebooks) {
49+
model.fromJSON({
50+
cells: notebooks[selected]?.cells ?? [],
51+
metadata: {
52+
deepnote: {
53+
notebooks
54+
}
55+
},
56+
nbformat: 4,
57+
nbformat_minor: 0
58+
});
5059
model.dirty = false;
5160
}
5261

@@ -56,12 +65,13 @@ export class NotebookPicker extends ReactWidget {
5665

5766
render(): JSX.Element {
5867
const deepnoteMetadata = this.panel.context.model.getMetadata('deepnote');
59-
const metadataNames = deepnoteMetadata?.notebook_names;
60-
const names =
61-
Array.isArray(metadataNames) &&
62-
metadataNames.every(n => typeof n === 'string')
63-
? metadataNames
64-
: [];
68+
69+
const deepnoteMetadataValidated =
70+
deepnoteMetadataSchema.safeParse(deepnoteMetadata);
71+
72+
const names = deepnoteMetadataValidated.success
73+
? Object.values(deepnoteMetadataValidated.data.notebooks).map(n => n.name)
74+
: [];
6575

6676
return (
6777
<HTMLSelect

0 commit comments

Comments
 (0)