diff --git a/.editorconfig b/.editorconfig index 4f92a467d0..37bd57d7d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,3 +15,7 @@ insert_final_newline = true [{.travis.yml,npm-shrinkwrap.json,package.json}] indent_style = space indent_size = 4 + +[.github/{workflows,actions}/*.yml] +indent_style = space +indent_size = 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f47be9fa91..72b3113aaa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,6 +190,155 @@ jobs: - name: Run spell check run: npm run spell-check + integration-tests: + name: Integration Tests + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + permissions: + id-token: write + contents: read + packages: read + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + # os: [ubuntu-latest, windows-latest] # Windows commented out for now, can be re-enabled later + python: [python] + pythonVersion: ['3.12'] + tags: [ + '^[^@]+$|@mandatory|@kernelCore|@python|@jupyter', + '@widgets', + '@iw', + '@webview|@export|@lsp|@variableViewer', + '@debugger' + ] + # exclude: + # - os: windows-latest + # tags: '@widgets' + # - os: windows-latest + # tags: '@webview|@export|@lsp|@variableViewer' + env: + VSC_JUPYTER_FORCE_LOGGING: 'true' + VSC_PYTHON_FORCE_LOGGING: 'true' + VSC_JUPYTER_CI_TEST_VSC_CHANNEL: 'insiders' + DISABLE_INSIDERS_EXTENSION: 1 + PYTHON_VERSION: ${{ matrix.pythonVersion }} + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Setup Node.js + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + cache: 'npm' + node-version-file: '.nvmrc' + registry-url: 'https://npm.pkg.github.com' + scope: '@deepnote' + + - name: Setup Python ${{ matrix.pythonVersion }} + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + id: setupPythonVersion + with: + python-version: ${{ matrix.pythonVersion }} + + - name: Set CI Python Path + run: echo "CI_PYTHON_PATH=${{ steps.setupPythonVersion.outputs.python-path }}" >> $GITHUB_ENV + + # Cache pip dependencies + - name: Cache pip dependencies + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.pythonVersion }}-${{ hashFiles('build/venv-test-ipywidgets8-requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.pythonVersion }}- + + - name: Install dependencies + run: npm ci --prefer-offline --no-audit + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install Python test requirements + run: | + python --version + python -c "import sys;print(sys.executable)" + python -m pip install --upgrade pip wheel + python -m pip --disable-pip-version-check install -r build/venv-test-ipywidgets8-requirements.txt + python -m pip install packaging + python ./pythonFiles/install_debugpy.py + python -m ipykernel install --user + + - name: Install screen capture dependencies + run: sudo apt-get update && sudo apt-get install --fix-missing imagemagick x11-xserver-utils + + - name: Generate Tag Variable + run: echo "TAGSVAR=${{ matrix.tags }}" >> $GITHUB_ENV + + - name: Generate Friendly Variable + run: echo "TAGS_NAME=${TAGSVAR//[^a-zA-Z]/_}" >> $GITHUB_ENV + + - name: Compile TypeScript + run: npm run compile + env: + VSC_JUPYTER_CI_FAST_COMPILATION: 1 + VSC_JUPYTER_CI_TEST_GREP: ${{ matrix.tags }} + + - name: Create temp folder for user data dir + run: | + echo "VSC_JUPYTER_USER_DATA_DIR=$(mktemp -d)" >> $GITHUB_ENV + echo ${{env.VSC_JUPYTER_USER_DATA_DIR}} is user data dir + + # Windows-specific steps (commented out for now) + # - name: Create temp folder for user data dir (Windows) + # if: matrix.os == 'windows-latest' + # run: | + # echo "VSC_JUPYTER_USER_DATA_DIR=$env:USERPROFILE\AppData\Local\Temp" >> $Env:GITHUB_ENV + # echo ${{env.VSC_JUPYTER_USER_DATA_DIR}} is user data dir + # shell: pwsh + + - name: Set xvfb parameters + run: echo "xvfbCommand=--server-args=\"-screen 0 1024x768x24\"" >> $GITHUB_ENV + + - name: Run integration tests + uses: GabrielBB/xvfb-action@b706e4e27b14669b486812790492dc50ca16b465 # v1.7 + with: + run: ${{ env.xvfbCommand }} npm run test:integration + env: + VSC_JUPYTER_FORCE_LOGGING: 1 + VSC_PYTHON_FORCE_LOGGING: 1 + VSC_JUPYTER_CI_TEST_VSC_CHANNEL: 'insiders' + VSC_JUPYTER_CI_TEST_GREP: ${{ matrix.tags }} + + # Windows-specific test execution (commented out for now) + # - name: Run integration tests (Windows) + # if: matrix.os == 'windows-latest' + # run: npm run test:integration:windows + # env: + # VSC_JUPYTER_FORCE_LOGGING: 1 + # VSC_PYTHON_FORCE_LOGGING: 1 + # VSC_JUPYTER_CI_TEST_VSC_CHANNEL: 'insiders' + # VSC_JUPYTER_CI_TEST_GREP: ${{ matrix.tags }} + # VSC_PYTHON_LOG_FILE: ${{env.VSC_JUPYTER_USER_DATA_DIR}}/logs/python.log + + - name: Upload VS Code logs + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 #v5 + if: failure() + with: + name: VSCodeLogs-${{ matrix.os }}-${{ matrix.pythonVersion }}-${{ env.TAGS_NAME }} + path: '${{env.VSC_JUPYTER_USER_DATA_DIR}}/logs/**/*' + retention-days: 7 + + - name: Upload test result files + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 #v5 + if: always() + with: + name: TestLogs-${{ matrix.os }}-${{ matrix.pythonVersion }}-${{ env.TAGS_NAME }} + path: './logs/*' + retention-days: 7 + + - name: Verify there are no unhandled errors + run: npx gulp verifyUnhandledErrors + audit-prod: name: Audit - Production runs-on: ubuntu-latest diff --git a/src/notebooks/deepnote/deepnoteExplorerView.ts b/src/notebooks/deepnote/deepnoteExplorerView.ts index 07809e0876..e8f180e3fa 100644 --- a/src/notebooks/deepnote/deepnoteExplorerView.ts +++ b/src/notebooks/deepnote/deepnoteExplorerView.ts @@ -1,7 +1,8 @@ import { injectable, inject } from 'inversify'; import { commands, window, workspace, type TreeView, Uri, l10n } from 'vscode'; import * as yaml from 'js-yaml'; -import { convertIpynbFilesToDeepnoteFile } from '@deepnote/convert'; +// NOTE: Use dynamic import for '@deepnote/convert' to avoid activation failures in test hosts +// where the package may not be resolvable. We only import it when needed. import { IExtensionContext } from '../../platform/common/types'; import { IDeepnoteNotebookManager } from '../types'; @@ -357,6 +358,7 @@ export class DeepnoteExplorerView { const outputFileName = `${projectName}.deepnote`; const outputPath = Uri.joinPath(workspaceFolder.uri, outputFileName).path; + const { convertIpynbFilesToDeepnoteFile } = await import('@deepnote/convert'); await convertIpynbFilesToDeepnoteFile(inputFilePaths, { outputPath: outputPath, projectName: projectName @@ -429,6 +431,7 @@ export class DeepnoteExplorerView { // File doesn't exist, continue } + const { convertIpynbFilesToDeepnoteFile } = await import('@deepnote/convert'); await convertIpynbFilesToDeepnoteFile(inputFilePaths, { outputPath: outputUri.path, projectName: projectName diff --git a/src/test/constants.node.ts b/src/test/constants.node.ts index 7ef5609002..d080bb4710 100644 --- a/src/test/constants.node.ts +++ b/src/test/constants.node.ts @@ -16,7 +16,7 @@ export const EXTENSION_TEST_DIR_FOR_FILES = path.join( 'datascience', 'temp' ); -export const JVSC_EXTENSION_ID_FOR_TESTS = 'ms-toolsai.jupyter'; +export const JVSC_EXTENSION_ID_FOR_TESTS = 'Deepnote.vscode-deepnote'; export const SMOKE_TEST_EXTENSIONS_DIR = path.join( EXTENSION_ROOT_DIR_FOR_TESTS, diff --git a/src/test/constants.ts b/src/test/constants.ts index 82c2a0b38d..36000a5f9f 100644 --- a/src/test/constants.ts +++ b/src/test/constants.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export const JVSC_EXTENSION_ID_FOR_TESTS = 'ms-toolsai.jupyter'; +export const JVSC_EXTENSION_ID_FOR_TESTS = 'Deepnote.vscode-deepnote'; export const PerformanceExtensionId = 'ms-toolsai.vscode-notebook-perf'; export type TestSettingsType = { diff --git a/src/test/datascience/setupTestEnvs.sh b/src/test/datascience/setupTestEnvs.sh index 67cc0bfb30..f15867bb37 100644 --- a/src/test/datascience/setupTestEnvs.sh +++ b/src/test/datascience/setupTestEnvs.sh @@ -7,7 +7,7 @@ python --version python -c "import sys;print(sys.executable)" uv pip install ipykernel python -m ipykernel install --user --name .venvkernel --display-name .venvkernel -uv pip uninstall jedi --yes +uv pip uninstall jedi uv pip install jedi==0.17.2 uv pip install ipywidgets==7.7.2 @@ -16,6 +16,6 @@ python --version python -c "import sys;print(sys.executable)" uv pip install ipykernel python -m ipykernel install --user --name .venvnokernel --display-name .venvnokernel -uv pip uninstall jedi --yes +uv pip uninstall jedi uv pip install jedi==0.17.2 -uv pip uninstall ipykernel --yes +uv pip uninstall ipykernel