diff --git a/.github/workflows/languages.yaml b/.github/workflows/languages.yaml index 8bc8e712f..7e97158cf 100644 --- a/.github/workflows/languages.yaml +++ b/.github/workflows/languages.yaml @@ -3,7 +3,7 @@ name: languages on: push: branches: [main, test-me-*] - tags: + tags: '*' pull_request: concurrency: @@ -63,8 +63,6 @@ jobs: echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH" shell: bash if: matrix.os == 'windows-latest' && matrix.language == 'perl' - - run: testing/get-swift.sh - if: matrix.os == 'ubuntu-latest' && matrix.language == 'swift' - name: install deps run: python -mpip install -e . -r requirements-dev.txt diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f281dcf27..903d24780 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,7 +3,7 @@ name: main on: push: branches: [main, test-me-*] - tags: + tags: '*' pull_request: concurrency: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ffd305878..7810d2294 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,22 +10,22 @@ repos: - id: name-tests-test - id: requirements-txt-fixer - repo: https://github.com/asottile/setup-cfg-fmt - rev: v2.2.0 + rev: v2.3.0 hooks: - id: setup-cfg-fmt -- repo: https://github.com/asottile/reorder_python_imports +- repo: https://github.com/asottile/reorder-python-imports rev: v3.9.0 hooks: - id: reorder-python-imports exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/) args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.4.0 + rev: v2.5.1 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.3.2 + rev: v3.6.0 hooks: - id: pyupgrade args: [--py38-plus] @@ -38,7 +38,7 @@ repos: hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 + rev: v1.3.0 hooks: - id: mypy additional_dependencies: [types-all] diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e58ff25..722e8ffa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +3.3.3 - 2023-06-13 +================== + +### Fixes +- Work around OS packagers setting `--install-dir` / `--bin-dir` in gem settings. + - #2905 PR by @jaysoffian. + - #2799 issue by @lmilbaum. + +3.3.2 - 2023-05-17 +================== + +### Fixes +- Work around `r` on windows sometimes double-un-quoting arguments. + - #2885 PR by @lorenzwalthert. + - #2870 issue by @lorenzwalthert. + +3.3.1 - 2023-05-02 +================== + +### Fixes +- Work around `git` partial clone bug for `autoupdate` on windows. + - #2866 PR by @asottile. + - #2865 issue by @adehad. + 3.3.0 - 2023-05-01 ================== diff --git a/pre_commit/commands/autoupdate.py b/pre_commit/commands/autoupdate.py index 178648108..e7725fdc4 100644 --- a/pre_commit/commands/autoupdate.py +++ b/pre_commit/commands/autoupdate.py @@ -67,6 +67,8 @@ def update(self, tags_only: bool, freeze: bool) -> RevInfo: rev, frozen = exact, rev try: + # workaround for windows -- see #2865 + cmd_output_b(*_git, 'show', f'{rev}:{C.MANIFEST_FILE}') cmd_output(*_git, 'checkout', rev, '--', C.MANIFEST_FILE) except CalledProcessError: pass # this will be caught by manifest validating code diff --git a/pre_commit/languages/r.py b/pre_commit/languages/r.py index 138a26e1e..6feb06523 100644 --- a/pre_commit/languages/r.py +++ b/pre_commit/languages/r.py @@ -4,6 +4,8 @@ import os import shlex import shutil +import tempfile +import textwrap from typing import Generator from typing import Sequence @@ -21,6 +23,19 @@ health_check = lang_base.basic_health_check +@contextlib.contextmanager +def _r_code_in_tempfile(code: str) -> Generator[str, None, None]: + """ + To avoid quoting and escaping issues, avoid `Rscript [options] -e {expr}` + but use `Rscript [options] path/to/file_with_expr.R` + """ + with tempfile.TemporaryDirectory() as tmpdir: + fname = os.path.join(tmpdir, 'script.R') + with open(fname, 'w') as f: + f.write(_inline_r_setup(textwrap.dedent(code))) + yield fname + + def get_env_patch(venv: str) -> PatchesT: return ( ('R_PROFILE_USER', os.path.join(venv, 'activate.R')), @@ -93,6 +108,8 @@ def install_environment( version: str, additional_dependencies: Sequence[str], ) -> None: + lang_base.assert_version_default('r', version) + env_dir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) os.makedirs(env_dir, exist_ok=True) shutil.copy(prefix.path('renv.lock'), env_dir) @@ -127,20 +144,19 @@ def install_environment( }} """ - cmd_output_b( - _rscript_exec(), '--vanilla', '-e', - _inline_r_setup(r_code_inst_environment), - cwd=env_dir, - ) + with _r_code_in_tempfile(r_code_inst_environment) as f: + cmd_output_b(_rscript_exec(), '--vanilla', f, cwd=env_dir) + if additional_dependencies: r_code_inst_add = 'renv::install(commandArgs(trailingOnly = TRUE))' with in_env(prefix, version): - cmd_output_b( - _rscript_exec(), *RSCRIPT_OPTS, '-e', - _inline_r_setup(r_code_inst_add), - *additional_dependencies, - cwd=env_dir, - ) + with _r_code_in_tempfile(r_code_inst_add) as f: + cmd_output_b( + _rscript_exec(), *RSCRIPT_OPTS, + f, + *additional_dependencies, + cwd=env_dir, + ) def _inline_r_setup(code: str) -> str: @@ -148,11 +164,16 @@ def _inline_r_setup(code: str) -> str: Some behaviour of R cannot be configured via env variables, but can only be configured via R options once R has started. These are set here. """ - with_option = f"""\ - options(install.packages.compile.from.source = "never", pkgType = "binary") - {code} - """ - return with_option + with_option = [ + textwrap.dedent("""\ + options( + install.packages.compile.from.source = "never", + pkgType = "binary" + ) + """), + code, + ] + return '\n'.join(with_option) def run_hook( diff --git a/pre_commit/languages/ruby.py b/pre_commit/languages/ruby.py index 76631f253..c88269f24 100644 --- a/pre_commit/languages/ruby.py +++ b/pre_commit/languages/ruby.py @@ -114,6 +114,8 @@ def _install_ruby( def install_environment( prefix: Prefix, version: str, additional_dependencies: Sequence[str], ) -> None: + envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version) + if version != 'system': # pragma: win32 no cover _install_rbenv(prefix, version) with in_env(prefix, version): @@ -135,6 +137,8 @@ def install_environment( 'gem', 'install', '--no-document', '--no-format-executable', '--no-user-install', + '--install-dir', os.path.join(envdir, 'gems'), + '--bindir', os.path.join(envdir, 'gems', 'bin'), *prefix.star('.gem'), *additional_dependencies, ), ) diff --git a/setup.cfg b/setup.cfg index 8dffb6b75..88302e752 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = pre_commit -version = 3.3.0 +version = 3.3.3 description = A framework for managing and maintaining multi-language pre-commit hooks. long_description = file: README.md long_description_content_type = text/markdown @@ -8,7 +8,7 @@ url = https://github.com/pre-commit/pre-commit author = Anthony Sottile author_email = asottile@umich.edu license = MIT -license_file = LICENSE +license_files = LICENSE classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 diff --git a/testing/get-swift.sh b/testing/get-swift.sh deleted file mode 100755 index dfe093912..000000000 --- a/testing/get-swift.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -# This is a script used in CI to install swift -set -euo pipefail - -. /etc/lsb-release -if [ "$DISTRIB_CODENAME" = "jammy" ]; then - SWIFT_URL='https://download.swift.org/swift-5.7.1-release/ubuntu2204/swift-5.7.1-RELEASE/swift-5.7.1-RELEASE-ubuntu22.04.tar.gz' - SWIFT_HASH='7f60291f5088d3e77b0c2364beaabd29616ee7b37260b7b06bdbeb891a7fe161' -else - echo "unknown dist: ${DISTRIB_CODENAME}" 1>&2 - exit 1 -fi - -check() { - echo "$SWIFT_HASH $TGZ" | sha256sum --check -} - -TGZ="$HOME/.swift/swift.tar.gz" -mkdir -p "$(dirname "$TGZ")" -if ! check >& /dev/null; then - rm -f "$TGZ" - curl --location --silent --output "$TGZ" "$SWIFT_URL" - check -fi - -mkdir -p /tmp/swift -tar -xf "$TGZ" --strip 1 --directory /tmp/swift - -echo '/tmp/swift/usr/bin' >> "$GITHUB_PATH" diff --git a/testing/languages b/testing/languages index 5e8fc9e4f..f4804c7e5 100755 --- a/testing/languages +++ b/testing/languages @@ -16,6 +16,15 @@ EXCLUDED = frozenset(( )) +def _always_run() -> frozenset[str]: + ret = ['.github/workflows/languages.yaml', 'testing/languages'] + ret.extend( + os.path.join('pre_commit/resources', fname) + for fname in os.listdir('pre_commit/resources') + ) + return frozenset(ret) + + def _lang_files(lang: str) -> frozenset[str]: prog = f'''\ import json @@ -47,10 +56,14 @@ def main() -> int: if fname.endswith('.py') and fname != '__init__.py' ] + triggers_all = _always_run() + for fname in triggers_all: + assert os.path.exists(fname), fname + if not args.all: with concurrent.futures.ThreadPoolExecutor(os.cpu_count()) as exe: by_lang = { - lang: files + lang: files | triggers_all for lang, files in zip(langs, exe.map(_lang_files, langs)) } diff --git a/testing/zipapp/Dockerfile b/testing/zipapp/Dockerfile index 7c74c1b2e..ea967e383 100644 --- a/testing/zipapp/Dockerfile +++ b/testing/zipapp/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:focal +FROM ubuntu:jammy RUN : \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ @@ -11,4 +11,4 @@ RUN : \ ENV LANG=C.UTF-8 PATH=/venv/bin:$PATH RUN : \ && python3 -mvenv /venv \ - && pip install --no-cache-dir pip setuptools wheel no-manylinux --upgrade + && pip install --no-cache-dir pip distlib no-manylinux --upgrade diff --git a/testing/zipapp/make b/testing/zipapp/make index 37b5c355d..165046f66 100755 --- a/testing/zipapp/make +++ b/testing/zipapp/make @@ -4,7 +4,6 @@ from __future__ import annotations import argparse import base64 import hashlib -import importlib.resources import io import os.path import shutil @@ -42,10 +41,17 @@ def _add_shim(dest: str) -> None: with zipfile.ZipFile(bio, 'w') as zipf: zipf.write(shim, arcname='__main__.py') - with open(os.path.join(dest, 'python.exe'), 'wb') as f: - f.write(importlib.resources.read_binary('distlib', 't32.exe')) - f.write(b'#!py.exe -3\n') - f.write(bio.getvalue()) + with tempfile.TemporaryDirectory() as tmpdir: + _exit_if_retv( + 'podman', 'run', '--rm', '--volume', f'{tmpdir}:/out:rw', IMG, + 'cp', '/venv/lib/python3.10/site-packages/distlib/t32.exe', '/out', + ) + + with open(os.path.join(dest, 'python.exe'), 'wb') as f: + with open(os.path.join(tmpdir, 't32.exe'), 'rb') as t32: + f.write(t32.read()) + f.write(b'#!py.exe -3\n') + f.write(bio.getvalue()) def _write_cache_key(version: str, wheeldir: str, dest: str) -> None: