diff --git a/.github/actions/pre-test/action.yml b/.github/actions/pre-test/action.yml index a7bf0abe..608c0cd1 100644 --- a/.github/actions/pre-test/action.yml +++ b/.github/actions/pre-test/action.yml @@ -19,6 +19,7 @@ runs: echo 'C:\Strawberry\perl\site\bin' >> "$GITHUB_PATH" echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" + testing/get-coursier.sh testing/get-dart.sh - name: setup (linux) shell: bash diff --git a/pre_commit/languages/coursier.py b/pre_commit/languages/coursier.py index a6aea3fb..69c877d3 100644 --- a/pre_commit/languages/coursier.py +++ b/pre_commit/languages/coursier.py @@ -1,13 +1,14 @@ from __future__ import annotations import contextlib -import os +import os.path from typing import Generator from typing import Sequence from pre_commit.envcontext import envcontext from pre_commit.envcontext import PatchesT from pre_commit.envcontext import Var +from pre_commit.errors import FatalError from pre_commit.languages import helpers from pre_commit.parse_shebang import find_executable from pre_commit.prefix import Prefix @@ -23,9 +24,8 @@ def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], -) -> None: # pragma: win32 no cover +) -> None: helpers.assert_version_default('coursier', version) - helpers.assert_no_additional_deps('coursier', additional_dependencies) # Support both possible executable names (either "cs" or "coursier") executable = find_executable('cs') or find_executable('coursier') @@ -37,29 +37,40 @@ def install_environment( envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) channel = prefix.path('.pre-commit-channel') - for app_descriptor in os.listdir(channel): - _, app_file = os.path.split(app_descriptor) - app, _ = os.path.splitext(app_file) - helpers.run_setup_cmd( - prefix, - ( - executable, - 'install', - '--default-channels=false', - f'--channel={channel}', - app, - f'--dir={envdir}', - ), + if os.path.isdir(channel): + for app_descriptor in os.listdir(channel): + _, app_file = os.path.split(app_descriptor) + app, _ = os.path.splitext(app_file) + helpers.run_setup_cmd( + prefix, + ( + executable, + 'install', + '--default-channels=false', + '--channel', channel, + '--dir', envdir, + app, + ), + ) + elif not additional_dependencies: + raise FatalError( + 'expected .pre-commit-channel dir or additional_dependencies', ) + if additional_dependencies: + install_cmd = ( + executable, 'install', '--dir', envdir, *additional_dependencies, + ) + helpers.run_setup_cmd(prefix, install_cmd) -def get_env_patch(target_dir: str) -> PatchesT: # pragma: win32 no cover + +def get_env_patch(target_dir: str) -> PatchesT: return ( ('PATH', (target_dir, os.pathsep, Var('PATH'))), ) -@contextlib.contextmanager # pragma: win32 no cover +@contextlib.contextmanager def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]: envdir = helpers.environment_dir(prefix, ENVIRONMENT_DIR, version) with envcontext(get_env_patch(envdir)): diff --git a/testing/get-coursier.ps1 b/testing/get-coursier.ps1 deleted file mode 100755 index 42e56354..00000000 --- a/testing/get-coursier.ps1 +++ /dev/null @@ -1,11 +0,0 @@ -$wc = New-Object System.Net.WebClient - -$coursier_url = "https://github.com/coursier/coursier/releases/download/v2.0.5/cs-x86_64-pc-win32.exe" -$coursier_dest = "C:\coursier\cs.exe" -$coursier_hash ="d63d497f7805261e1cd657b8aaa626f6b8f7264cdb68219b2e6be9dd882033a9" - -New-Item -Path "C:\" -Name "coursier" -ItemType "directory" -$wc.DownloadFile($coursier_url, $coursier_dest) -if ((Get-FileHash $coursier_dest -Algorithm SHA256).Hash -ne $coursier_hash) { - throw "Invalid coursier file" -} diff --git a/testing/get-coursier.sh b/testing/get-coursier.sh index 6033c3e3..958e73b2 100755 --- a/testing/get-coursier.sh +++ b/testing/get-coursier.sh @@ -1,15 +1,29 @@ #!/usr/bin/env bash -# This is a script used in CI to install coursier set -euo pipefail -COURSIER_URL="https://github.com/coursier/coursier/releases/download/v2.0.0/cs-x86_64-pc-linux" -COURSIER_HASH="e2e838b75bc71b16bcb77ce951ad65660c89bda7957c79a0628ec7146d35122f" -ARTIFACT="/tmp/coursier/cs" +if [ "$OSTYPE" = msys ]; then + URL='https://github.com/coursier/coursier/releases/download/v2.1.0-RC4/cs-x86_64-pc-win32.zip' + SHA256='0d07386ff0f337e3e6264f7dde29d137dda6eaa2385f29741435e0b93ccdb49d' + TARGET='/tmp/coursier/cs.zip' + + unpack() { + unzip "$TARGET" -d /tmp/coursier + mv /tmp/coursier/cs-*.exe /tmp/coursier/cs.exe + cygpath -w /tmp/coursier >> "$GITHUB_PATH" + } +else + URL='https://github.com/coursier/coursier/releases/download/v2.1.0-RC4/cs-x86_64-pc-linux.gz' + SHA256='176e92e08ab292531aa0c4993dbc9f2c99dec79578752f3b9285f54f306db572' + TARGET=/tmp/coursier/cs.gz + + unpack() { + gunzip "$TARGET" + chmod +x /tmp/coursier/cs + echo /tmp/coursier >> "$GITHUB_PATH" + } +fi mkdir -p /tmp/coursier -rm -f "$ARTIFACT" -curl --location --silent --output "$ARTIFACT" "$COURSIER_URL" -echo "$COURSIER_HASH $ARTIFACT" | sha256sum --check -chmod ugo+x /tmp/coursier/cs - -echo '/tmp/coursier' >> "$GITHUB_PATH" +curl --location --silent --output "$TARGET" "$URL" +echo "$SHA256 $TARGET" | sha256sum --check +unpack diff --git a/testing/language_helpers.py b/testing/language_helpers.py new file mode 100644 index 00000000..02e47a00 --- /dev/null +++ b/testing/language_helpers.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import os +from typing import Sequence + +import pre_commit.constants as C +from pre_commit.languages.all import Language +from pre_commit.prefix import Prefix + + +def run_language( + path: os.PathLike[str], + language: Language, + exe: str, + args: Sequence[str] = (), + file_args: Sequence[str] = (), + version: str = C.DEFAULT, + deps: Sequence[str] = (), +) -> tuple[int, bytes]: + prefix = Prefix(str(path)) + + language.install_environment(prefix, version, deps) + with language.in_env(prefix, version): + ret, out = language.run_hook( + prefix, + exe, + args, + file_args, + require_serial=True, + color=False, + ) + out = out.replace(b'\r\n', b'\n') + return ret, out diff --git a/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json b/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json deleted file mode 100644 index 37f401e2..00000000 --- a/testing/resources/coursier_hooks_repo/.pre-commit-channel/echo-java.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "repositories": [ - "central" - ], - "dependencies": [ - "io.get-coursier:echo:latest.stable" - ] -} diff --git a/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml deleted file mode 100644 index d4a143b3..00000000 --- a/testing/resources/coursier_hooks_repo/.pre-commit-hooks.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- id: echo-java - name: echo-java - description: echo from java - entry: echo-java - language: coursier diff --git a/testing/util.py b/testing/util.py index e807f048..324f1f6c 100644 --- a/testing/util.py +++ b/testing/util.py @@ -42,10 +42,6 @@ def cmd_output_mocked_pre_commit_home( return ret, out.replace('\r\n', '\n'), None -skipif_cant_run_coursier = pytest.mark.skipif( - os.name == 'nt' or parse_shebang.find_executable('cs') is None, - reason="coursier isn't installed or can't be found", -) skipif_cant_run_docker = pytest.mark.skipif( os.name == 'nt' or not docker_is_running(), reason="Docker isn't running or can't be accessed", diff --git a/tests/languages/coursier_test.py b/tests/languages/coursier_test.py new file mode 100644 index 00000000..dbb746ca --- /dev/null +++ b/tests/languages/coursier_test.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +import pytest + +from pre_commit.errors import FatalError +from pre_commit.languages import coursier +from testing.language_helpers import run_language + + +def test_coursier_hook(tmp_path): + echo_java_json = '''\ +{ + "repositories": ["central"], + "dependencies": ["io.get-coursier:echo:latest.stable"] +} +''' + + channel_dir = tmp_path.joinpath('.pre-commit-channel') + channel_dir.mkdir() + channel_dir.joinpath('echo-java.json').write_text(echo_java_json) + + ret = run_language( + tmp_path, + coursier, + 'echo-java', + args=('Hello', 'World', 'from', 'coursier'), + ) + assert ret == (0, b'Hello World from coursier\n') + + +def test_coursier_hook_additional_dependencies(tmp_path): + ret = run_language( + tmp_path, + coursier, + 'scalafmt --version', + deps=('scalafmt:3.6.1',), + ) + assert ret == (0, b'scalafmt 3.6.1\n') + + +def test_error_if_no_deps_or_channel(tmp_path): + with pytest.raises(FatalError) as excinfo: + run_language(tmp_path, coursier, 'dne') + msg, = excinfo.value.args + assert msg == 'expected .pre-commit-channel dir or additional_dependencies' diff --git a/tests/repository_test.py b/tests/repository_test.py index 4043491b..5e4dff1e 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -32,7 +32,6 @@ from testing.fixtures import make_repo from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import get_resource_path -from testing.util import skipif_cant_run_coursier from testing.util import skipif_cant_run_docker from testing.util import skipif_cant_run_lua from testing.util import skipif_cant_run_swift @@ -199,15 +198,6 @@ def test_language_versioned_python_hook(tempdir_factory, store): ) -@skipif_cant_run_coursier # pragma: win32 no cover -def test_run_a_coursier_hook(tempdir_factory, store): - _test_hook_repo( - tempdir_factory, store, 'coursier_hooks_repo', - 'echo-java', - ['Hello World from coursier'], b'Hello World from coursier\n', - ) - - @skipif_cant_run_docker # pragma: win32 no cover def test_run_a_docker_hook(tempdir_factory, store): _test_hook_repo(