diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac1003e5..882bb97f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,9 +25,50 @@ jobs: cancel_others: 'true' skip_after_successful_duplicate: 'false' - test: + build: needs: pre_job if: needs.pre_job.outputs.should_skip != 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Use Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-in-project: true + + - name: Load cached venv + id: cached-poetry-dependencies + uses: actions/cache@v3 + with: + path: .venv + key: venv-${{ hashFiles('**/poetry.lock') }} + + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: poetry install + + - name: Build packages (sdist and wheel) + run: | + git describe --tags --abbrev=0 + poetry build + + - uses: actions/upload-artifact@v4 + with: + name: dist + path: "dist/*" + + + test: + needs: pre_job + if: false # needs.pre_job.outputs.should_skip != 'true' strategy: matrix: os: [ubuntu-latest, windows-latest] @@ -60,7 +101,7 @@ jobs: poe test test-pyodide: - needs: pre_job + needs: [pre_job, build] if: needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest steps: @@ -83,10 +124,14 @@ jobs: with: virtualenvs-in-project: true + - uses: actions/download-artifact@v4 + with: + name: dist + path: 'dist' + - name: Install Dependencies run: | poetry install --with test - poetry build cd tests/pyodide npm ci @@ -96,39 +141,67 @@ jobs: source $VENV poe test-pyodide - lint: - needs: pre_job + test-wasi: + needs: [pre_job, build] if: needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Use Python - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + + - name: Use Python "3.12" + uses: actions/setup-python@v5 with: - python-version: "3.x" + python-version: "3.12" + - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-in-project: true - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v3 + + - uses: actions/download-artifact@v4 with: - path: .venv - key: venv-${{ hashFiles('**/poetry.lock') }} - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --all-extras --with dev - - name: Run lints + name: dist + path: 'dist' + + - name: Install Dependencies + run: | + set -eux + + poetry install --with test + + # Wasmtime WASI Host + gh release download v16.0.0 \ + --repo bytecodealliance/wasmtime \ + --pattern 'wasmtime-v16.0.0-x86_64-linux.tar.xz' \ + --dir tests/wasi + + tar -xvf tests/wasi/wasmtime-v16.0.0-x86_64-linux.tar.xz \ + --wildcards 'wasmtime*/wasmtime' + + mv wasmtime-v16.0.0-x86_64-linux/wasmtime $HOME/.local/bin + + ls -l $HOME/.local/bin + wasmtime --help + + # WASI Python build + gh release download v3.12.1 \ + --repo brettcannon/cpython-wasi-build \ + --pattern 'python*sdk-20.zip' \ + --dir tests/wasi + + ls -l tests/wasi + + env: + GH_TOKEN: ${{ github.token }} + + - name: Run tests run: | source $VENV - poe lint + poe test-wasi - build: + lint: needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' + if: false # needs.pre_job.outputs.should_skip != 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -150,13 +223,8 @@ jobs: key: venv-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --all-extras - - name: Build packages (sdist and wheel) + run: poetry install --all-extras --with dev + - name: Run lints run: | - git describe --tags --abbrev=0 - poetry build - - name: Upload builds - uses: actions/upload-artifact@v3 - with: - name: build-artifacts - path: "dist/*" + source $VENV + poe lint diff --git a/examples/servers-next/code_actions.py b/examples/servers-next/code_actions.py index 7753b0ee..d5f05137 100644 --- a/examples/servers-next/code_actions.py +++ b/examples/servers-next/code_actions.py @@ -33,7 +33,7 @@ def code_actions(params: types.CodeActionParams): items = [] document_uri = params.text_document.uri - document = server.workspace.get_document(document_uri) + document = server.workspace.get_text_document(document_uri) start_line = params.range.start.line end_line = params.range.end.line diff --git a/pyproject.toml b/pyproject.toml index 5e6d6956..fdb543d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ asyncio_mode = "auto" [tool.poe.tasks] test-pyodide = "pytest tests/e2e --lsp-runtime pyodide" +test-wasi = "pytest tests/e2e --lsp-runtime wasi" ruff = "ruff check ." mypy = "mypy -p pygls" check_generated_client = "python scripts/check_client_is_uptodate.py" diff --git a/tests/conftest.py b/tests/conftest.py index 1581226b..1395469e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,7 +27,7 @@ from pygls import IS_PYODIDE from pygls import uris from pygls.feature_manager import FeatureManager -from pygls.lsp._client import LanguageClient +from pygls.lsp._client import LanguageClient as LanguageClient_ from pygls.workspace import Workspace DOC = """document @@ -36,7 +36,21 @@ with "😋" unicode. """ DOC_URI = uris.from_fs_path(__file__) or "" -SERVER_DIR = pathlib.Path(__file__, "..", "..", "examples", "servers-next").resolve() +REPO_DIR = pathlib.Path(__file__, "..", "..").resolve() +SERVER_DIR = REPO_DIR / "examples" / "servers-next" +WORKSPACE_DIR = REPO_DIR / "examples" / "servers" / "workspace" + + +class LanguageClient(LanguageClient_): + """Language client to use for testing.""" + + async def server_exit(self, server: asyncio.subprocess.Process): + # -15: terminated (probably by the client) + # 0: all ok + if server.returncode not in {-15, 0}: + if server.stderr is not None: + err = await server.stderr.read() + self.logger.debug("stderr:\n%s", err.decode("utf8")) def pytest_addoption(parser): @@ -65,12 +79,9 @@ def uri_for(runtime): Takes into account the runtime. """ - base_dir = pathlib.Path( - __file__, "..", "..", "examples", "servers", "workspace" - ).resolve() def fn(*args): - fpath = pathlib.Path(base_dir, *args) + fpath = pathlib.Path(WORKSPACE_DIR, *args) assert fpath.exists() if runtime == "pyodide": diff --git a/tests/wasi/.gitignore b/tests/wasi/.gitignore new file mode 100644 index 00000000..6f66c74b --- /dev/null +++ b/tests/wasi/.gitignore @@ -0,0 +1 @@ +*.zip \ No newline at end of file