-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add test coverage for the oldest supported Ruff version #270
Changes from 13 commits
7c8a933
1c12607
e4a270e
f315678
1603030
8a8f0ca
9a225b4
7f4a0ee
ee7fc02
1bed5c6
c7c63e9
3fd0e60
fbd9d55
e356f10
99894e7
0d5c284
31be9b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,12 +7,68 @@ on: | |
branches: [main] | ||
|
||
jobs: | ||
ci: | ||
check: | ||
name: Check | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: extractions/setup-just@v1 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: "3.11" | ||
cache: 'pip' | ||
- name: Install dependencies | ||
run: just install | ||
- name: Run checks | ||
run: just check | ||
ruff-versions: | ||
name: Generate test versions | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Install dependencies | ||
run: | | ||
sudo apt-get install -y ripgrep | ||
- name: Determine test versions | ||
id: set-versions | ||
run: | | ||
# Get the latest release version from GitHub | ||
LATEST=$( \ | ||
curl -L \ | ||
-H "Accept: application/vnd.github+json" \ | ||
-H "X-GitHub-Api-Version: 2022-11-28" \ | ||
https://api.github.com/repos/astral-sh/ruff/releases/latest \ | ||
| jq '.tag_name' --raw-output \ | ||
| cut -c2- \ | ||
) | ||
# Get the oldest supported version from the pyproject.toml | ||
OLDEST=$(rg -No '"ruff>=(.*)"' -r '$1' pyproject.toml) | ||
|
||
echo "::set-output name=versions::[\"$OLDEST\", \"$LATEST\"]" | ||
echo "::set-output name=oldest::$OLDEST | ||
echo "::set-output name=latest::$LATEST | ||
outputs: | ||
versions: ${{ steps.set-versions.outputs.versions }} | ||
oldest: ${{ steps.set-versions.outputs.oldest }} | ||
latest: ${{ steps.set-versions.outputs.latest }} | ||
test: | ||
name: Test | ||
needs: ruff-versions | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"] | ||
ruff-version: ${{ fromJson(needs.ruff-versions.outputs.versions) }} | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
|
||
exclude: | ||
- os: windows-latest | ||
ruff-version: ${{ needs.ruff-versions.outputs.oldest }} | ||
- os: macos-latest | ||
ruff-version: ${{ needs.ruff-versions.outputs.oldest }} | ||
Comment on lines
+66
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seemed overkill to include these in the matrix — it was a lot of testing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me, lowest and highest python versions would be sufficient in general |
||
|
||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- uses: extractions/setup-just@v1 | ||
|
@@ -22,9 +78,10 @@ jobs: | |
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
cache: 'pip' | ||
- name: Install dependencies | ||
run: just install | ||
- name: Run checks | ||
run: just check | ||
- name: Install test Ruff version | ||
run: pip install ruff==${{ matrix.ruff-version }} | ||
- name: Run tests | ||
run: just test |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from pathlib import Path | ||
|
||
import pytest | ||
from packaging.version import Version | ||
|
||
from ruff_lsp.server import _find_ruff_binary, _get_global_defaults, uris | ||
|
||
|
||
@pytest.fixture(scope="session") | ||
def ruff_version() -> Version: | ||
# Use the ruff-lsp directory as the workspace | ||
workspace_path = Path(__file__).parent.parent | ||
|
||
settings = { | ||
**_get_global_defaults(), # type: ignore[misc] | ||
"cwd": None, | ||
"workspacePath": workspace_path, | ||
"workspace": uris.from_fs_path(workspace_path), | ||
} | ||
|
||
return _find_ruff_binary(settings, version_requirement=None).version |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,9 +3,10 @@ | |
|
||
import os | ||
import tempfile | ||
import unittest | ||
from threading import Event | ||
|
||
from packaging.version import Version | ||
|
||
from tests.client import defaults, session, utils | ||
|
||
# Increase this if you want to attach a debugger | ||
|
@@ -16,11 +17,19 @@ | |
print(x) | ||
""" | ||
|
||
VERSION_REQUIREMENT_ASTRAL_DOCS = Version("0.0.291") | ||
|
||
|
||
class TestServer(unittest.TestCase): | ||
class TestServer: | ||
Comment on lines
-20
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I need the pytest fixture to be accessible here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to follow-up with a pull request that removes the class, but want to keep the diff focused here. |
||
maxDiff = None | ||
|
||
def test_linting_example(self) -> None: | ||
def test_linting_example(self, ruff_version: Version) -> None: | ||
expected_docs_url = ( | ||
"https://docs.astral.sh/ruff/" | ||
if ruff_version >= VERSION_REQUIREMENT_ASTRAL_DOCS | ||
else "https://beta.ruff.rs/docs/" | ||
) | ||
|
||
with tempfile.NamedTemporaryFile(suffix=".py") as fp: | ||
fp.write(CONTENTS.encode()) | ||
fp.flush() | ||
|
@@ -60,7 +69,7 @@ def _handler(params): | |
{ | ||
"code": "F401", | ||
"codeDescription": { | ||
"href": "https://docs.astral.sh/ruff/rules/unused-import" | ||
"href": expected_docs_url + "rules/unused-import" | ||
}, | ||
"data": { | ||
"fix": { | ||
|
@@ -88,7 +97,7 @@ def _handler(params): | |
{ | ||
"code": "F821", | ||
"codeDescription": { | ||
"href": "https://docs.astral.sh/ruff/rules/undefined-name" | ||
"href": expected_docs_url + "rules/undefined-name" | ||
}, | ||
"data": {"fix": None, "noqa_row": 3}, | ||
"message": "Undefined name `x`", | ||
|
@@ -102,9 +111,15 @@ def _handler(params): | |
], | ||
"uri": uri, | ||
} | ||
self.assertEqual(expected, actual) | ||
assert expected == actual | ||
|
||
def test_no_initialization_options(self, ruff_version: Version) -> None: | ||
expected_docs_url = ( | ||
"https://docs.astral.sh/ruff/" | ||
if ruff_version >= VERSION_REQUIREMENT_ASTRAL_DOCS | ||
else "https://beta.ruff.rs/docs/" | ||
) | ||
|
||
def test_no_initialization_options(self) -> None: | ||
with tempfile.NamedTemporaryFile(suffix=".py") as fp: | ||
fp.write(CONTENTS.encode()) | ||
fp.flush() | ||
|
@@ -149,7 +164,7 @@ def _handler(params): | |
{ | ||
"code": "F401", | ||
"codeDescription": { | ||
"href": "https://docs.astral.sh/ruff/rules/unused-import" | ||
"href": expected_docs_url + "rules/unused-import" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wish we could just store "fixtures by version" or something, rather than having to construct these and encode facts like "Which URL is present at which version?" in the test logic. Like, in Rust, we'd just run the command with different versions and snapshot the output, which feels easier to maintain and understand. I don't know if I have a concrete suggestion here -- more reacting to the increased logic in the tests now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm interesting yeah.. this whole bit would make more sense as a snapshot too. A strong case for us building Python test tooling <3 |
||
}, | ||
"data": { | ||
"fix": { | ||
|
@@ -177,7 +192,7 @@ def _handler(params): | |
{ | ||
"code": "F821", | ||
"codeDescription": { | ||
"href": "https://docs.astral.sh/ruff/rules/undefined-name" | ||
"href": expected_docs_url + "rules/undefined-name" | ||
}, | ||
"data": {"fix": None, "noqa_row": 3}, | ||
"message": "Undefined name `x`", | ||
|
@@ -191,4 +206,4 @@ def _handler(params): | |
], | ||
"uri": uri, | ||
} | ||
self.assertEqual(expected, actual) | ||
assert expected == actual |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's way more painful to extract the first matching group like this without ripgrep, afaict
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would honestly be fine hard-coding this and the latest version, since we already search-and-replace the latest version every time we upgrade the LSP. Fewer dependencies, easier to maintain (IMO). But of course I defer to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sed -rn 's/.*"ruff>=(.*).*",/\1/p' pyproject.toml
worksThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's just me but a sed invocation like that is entirely incomprehensible haha :)
I'd like to try this out since I wrote it up and haven't tried generating matrix test versions like this before, but at the first sign of trouble I'm happy to just switch to hard-coded versions.