Skip to content

Commit

Permalink
Merge branch 'master' into uprevPythonPackages
Browse files Browse the repository at this point in the history
  • Loading branch information
clintonsteiner authored Jan 7, 2025
2 parents f8d6b0d + 767e00e commit 925f271
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pyupgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ jobs:
from pyupgrade._main import main
from glob import glob
files = glob('**/*.py', recursive=True)
sys.exit(main(files + ['--py38-plus']))
sys.exit(main(files + ['--py39-plus']))
" || ( git diff ; false )
107 changes: 107 additions & 0 deletions .github/workflows/test-working-directory.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: "GH Action `working-directory:` test"

on: push # yamllint disable-line rule:truthy

jobs:
setup:
runs-on: ubuntu-latest
steps:
- name: Set up initial test repository
run: |
mkdir -p test-repo
cd test-repo
git init
git config user.email "[email protected]"
git config user.name "Test User"
git commit --allow-empty -m "Initial empty commit"
echo 'def hello(): return "Hello, World!"' > test.py
git add test.py
git commit -m "Add test.py file"
echo 'def hello(): return "Hello, World!"' > test.py
- name: Upload test repository
uses: actions/upload-artifact@v3
with:
name: test-repo
path: test-repo

test:
needs: setup
runs-on: ubuntu-latest
strategy:
matrix:
scenario:
- name: no-work-dir
working_directory: null # Consider it omitted
src: test.py
options: --check --diff
expected_exitcode: 2
- name: right-workdir
working_directory: test-repo
src: test.py
options: --check --diff
expected_exitcode: 1
- name: wrong-work-dir
working_directory: non-existent-dir
src: test.py
options: --check --diff
expected_exitcode: 21
- name: file-not-found
working_directory: test-repo
src: non_existent_file.py
options: --check --diff
expected_exitcode: 2
- name: invalid-arguments
working_directory: test-repo
src: test.py
options: --invalid-option
expected_exitcode: 3
- name: missing-deps
working_directory: test-repo
src: test.py
options: --flynt # not yet supported by the action
expected_exitcode: 4

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 10

- name: Download test repository
uses: actions/download-artifact@v3
with:
name: test-repo
path: ${{ runner.temp }}/test-repo

- name: "Run Darker - ${{ matrix.scenario.name }}"
uses: ./
continue-on-error: true
id: darker-run
with:
version: "@gh-action-working-directory"
options: ${{ matrix.scenario.options }}
# In the action, '.' is the default value used if `working-directory` omitted
working-directory: >-
${{
matrix.scenario.working_directory == null && '.'
|| format('{0}/{1}', runner.temp, matrix.scenario.working_directory)
}}
src: ${{ matrix.scenario.src }}
revision: HEAD

- name: Check exit code
if: >-
steps.darker-run.outputs.exitcode != matrix.scenario.expected_exitcode
run: |
echo "::error::Expected exit code ${{ matrix.scenario.expected_exitcode }}"
echo "::error::Darker exited with ${{ steps.darker-run.outputs.exitcode }}"
exit 1
- name: Verify diff output for right-workdir scenario
if: >
matrix.scenario.name == 'right-workdir' &&
!contains(steps.darker-run.outputs.stdout, '@@')
run: |
echo "::error::Darker did not output a diff as expected"
exit 1
10 changes: 8 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Added
- Display exit code in parentheses after error message.
- Do not reformat renamed files.
- CI workflow to post recent project activity in a discussion. Triggered manually.
- CI "future" test now tests against ``main`` of Darkgraylib_ in addition to Black_,
Flynt_ and isort_.
- The ``--preview`` configuration flag is now supported in the configuration files for
Darker and Black
- Prevent Pylint from updating beyond version 3.2.7 due to dropped Python 3.8 support.
Expand All @@ -34,8 +36,9 @@ Removed
Fixed
-----
- Update ``darkgray-dev-tools`` for Pip >= 24.1 compatibility.
- Update to Darkgraylib 2.0.1 to fix the configuration dump, the output of ``--version``
and the Git "dubious ownership" issue (see below).
- Update to Darkgraylib 2.2.0 to fix the configuration dump, the output of
``--version``, the Git "dubious ownership" issue, and source code line splitting
(see below).
- In the configuration dump printed when ``-vv`` verbosity is used, the configuration
section is now correctly named ``[tool.darker]`` instead of ``[tool.darkgraylib]``.
- Pass Graylint version to `~darkgraylib.command_line.make_argument_parser` to make
Expand All @@ -44,6 +47,8 @@ Fixed
- Work around a `pathlib.Path.resolve` bug in Python 3.8 and 3.9 on Windows.
The work-around should be removed when Python 3.8 and 3.9 are no longer supported.
- Add missing configuration flag for Flynt_.
- Only split source code lines at Python's universal newlines (LF, CRLF, CR).
- The Darker GitHub action now respects the ``working-directory`` input option.


2.1.1_ - 2024-04-16
Expand Down Expand Up @@ -686,4 +691,5 @@ Added
.. _pydocstyle: http://www.pydocstyle.org/
.. _Ruff: https://astral.sh/ruff
.. _Black: https://black.readthedocs.io/
.. _isort: https://pycqa.github.io/isort/
.. _NixOS: https://nixos.org/
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ An example ``pyproject.toml`` configuration file:
line-length = 88 # Overridden by [tool.darker] above
skip-magic-trailing-comma = false
skip-string-normalization = false
target-version = ["py38", "py39", "py310", "py311", "py312"] # Overridden above
target-version = ["py39", "py310", "py311", "py312"] # Overridden above
exclude = "test_*\.py"
extend_exclude = "/generated/"
force_exclude = ".*\.pyi"
Expand Down
26 changes: 25 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ inputs:
NOTE: Baseline linting has been moved to the Graylint package.
required: false
default: ''
working-directory:
description: >-
Directory to run Darker in, either absolute or relative to
$GITHUB_WORKSPACE. By default, Darker is run in $GITHUB_WORKSPACE.
required: false
default: '.'
outputs:
exitcode:
description: "Exit code of Darker"
value: ${{ steps.darker.outputs.exitcode }}
stdout:
description: "Standard output of Darker"
value: ${{ steps.darker.outputs.stdout }}
branding:
color: "black"
icon: "check-circle"
Expand All @@ -35,8 +48,18 @@ runs:
steps:
- name: Commit Range
id: commit-range
uses: akaihola/darker/.github/actions/[email protected]
uses: ./.github/actions/commit-range
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
cache: 'pip'
- name: Install dependencies
run: |
pip install pip-requirements-parser
shell: bash
- name: Run Darker
id: darker
run: |
# Exists since using github.action_path + path to main script doesn't
# work because bash interprets the backslashes in github.action_path
Expand Down Expand Up @@ -68,5 +91,6 @@ runs:
INPUT_REVISION: ${{ inputs.revision }}
INPUT_LINT: ${{ inputs.lint }}
INPUT_COMMIT_RANGE: ${{ steps.commit-range.outputs.commit-range }}
INPUT_WORKING_DIRECTORY: ${{ inputs.working-directory }}
pythonioencoding: utf-8
shell: bash
63 changes: 49 additions & 14 deletions action/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,68 @@
SRC = os.getenv("INPUT_SRC", default="")
VERSION = os.getenv("INPUT_VERSION", default="")
REVISION = os.getenv("INPUT_REVISION") or os.getenv("INPUT_COMMIT_RANGE") or "HEAD^"
WORKING_DIRECTORY = os.getenv("INPUT_WORKING_DIRECTORY", ".")

if os.getenv("INPUT_LINT", default=""):
print(
"::notice:: Baseline linting has been moved to the Graylint package."
" See https://pypi.org/project/graylint for more information.",
)

run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True) # nosec

def set_github_output(key: str, val: str) -> None:
"""Write a key-value pair to the output file."""
with Path(os.environ["GITHUB_OUTPUT"]).open("a", encoding="UTF-8") as f:
if "\n" in val:
print(f"{key}<<DARKER_ACTION_EOF", file=f)
print(val, file=f, end="" if val.endswith("\n") else "\n")
print("DARKER_ACTION_EOF", file=f)
else:
print(f"{key}={val}", file=f)


def exit_with_exitcode(exitcode: int) -> None:
"""Write the exit code to the output file and exit with it."""
set_github_output("exitcode", str(exitcode))
sys.exit(exitcode)


# Check if the working directory exists
if not os.path.isdir(WORKING_DIRECTORY):
print(f"::error::Working directory does not exist: {WORKING_DIRECTORY}", flush=True)
exit_with_exitcode(21)


def pip_install(*packages):
"""Install the specified Python packages using a pip subprocess."""
python = str(ENV_BIN / "python")
args = [python, "-m", "pip", "install", *packages]
pip_proc = run( # nosec
args,
check=False,
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
)
print(pip_proc.stdout, end="")
if pip_proc.returncode:
print(f"::error::Failed to install {' '.join(packages)}.", flush=True)
sys.exit(pip_proc.returncode)


if not ENV_PATH.exists():
run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True) # nosec

req = ["darker[black,color,isort]"]
if VERSION:
if VERSION.startswith("@"):
req[0] = f"git+https://github.com/akaihola/darker{VERSION}#egg={req[0]}"
req[0] += f"@git+https://github.com/akaihola/darker{VERSION}"
elif VERSION.startswith(("~", "=", "<", ">")):
req[0] += VERSION
else:
req[0] += f"=={VERSION}"

pip_proc = run( # nosec
[str(ENV_BIN / "python"), "-m", "pip", "install"] + req,
check=False,
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
)
print(pip_proc.stdout, end="")
if pip_proc.returncode:
print(f"::error::Failed to install {' '.join(req)}.", flush=True)
sys.exit(pip_proc.returncode)
pip_install(*req)


base_cmd = [str(ENV_BIN / "darker")]
Expand All @@ -58,7 +91,9 @@
stderr=STDOUT,
env={**os.environ, "PATH": f"{ENV_BIN}:{os.environ['PATH']}"},
encoding="utf-8",
cwd=WORKING_DIRECTORY,
)
print(proc.stdout, end="")

sys.exit(proc.returncode)
set_github_output("stdout", proc.stdout)
exit_with_exitcode(proc.returncode)
44 changes: 36 additions & 8 deletions action/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ def patch_main(

def run(args, **kwargs):
returncode = pip_returncode if args[1:3] == ["-m", "pip"] else 0
return CompletedProcess(args, returncode, stdout="", stderr="")
return CompletedProcess(
args, returncode, stdout="Output\nfrom\nDarker", stderr=""
)

run_mock = Mock(wraps=run)
exit_ = Mock(side_effect=SysExitCalled)
Expand Down Expand Up @@ -78,7 +80,16 @@ def main_patch(
yield run_main_fixture


def test_creates_virtualenv(tmp_path, main_patch):
@pytest.fixture
def github_output(tmp_path: Path) -> Generator[Path]:
"""Fixture to set up a GitHub output file for the action"""
gh_output_filepath = tmp_path / "github.output"
with patch.dict("os.environ", {"GITHUB_OUTPUT": str(gh_output_filepath)}):

yield gh_output_filepath


def test_creates_virtualenv(tmp_path, main_patch, github_output):
"""The GitHub action creates a virtualenv for Darker"""
with pytest.raises(SysExitCalled):

Expand All @@ -99,8 +110,7 @@ def test_creates_virtualenv(tmp_path, main_patch):
dict(
run_main_env={"INPUT_VERSION": "@master"},
expect=[
"git+https://github.com/akaihola/darker"
"@master#egg=darker[black,color,isort]"
"darker[black,color,isort]@git+https://github.com/akaihola/darker@master"
],
),
dict(
Expand All @@ -112,7 +122,7 @@ def test_creates_virtualenv(tmp_path, main_patch):
expect=["darker[black,color,isort]"],
),
)
def test_installs_packages(tmp_path, main_patch, run_main_env, expect):
def test_installs_packages(tmp_path, main_patch, github_output, run_main_env, expect):
"""Darker, isort and linters are installed in the virtualenv using pip"""
with pytest.raises(SysExitCalled):

Expand Down Expand Up @@ -185,7 +195,12 @@ def test_installs_packages(tmp_path, main_patch, run_main_env, expect):
],
),
)
def test_runs_darker(tmp_path: Path, env: dict[str, str], expect: list[str]) -> None:
def test_runs_darker(
tmp_path: Path,
github_output: Generator[Path],
env: dict[str, str],
expect: list[str],
) -> None:
"""Configuration translates correctly into a Darker command line"""
with patch_main(tmp_path, env) as main_patch, pytest.raises(SysExitCalled):

Expand Down Expand Up @@ -218,15 +233,28 @@ def test_error_if_pip_fails(tmp_path, capsys):
)
assert (
capsys.readouterr().out.splitlines()[-1]
== "::error::Failed to install darker[black,color,isort]."
== "Darker::error::Failed to install darker[black,color,isort]."
)
main_patch.sys.exit.assert_called_once_with(42)


def test_exits(main_patch):
def test_exits(main_patch, github_output):
"""A successful run exits with a zero return code"""
with pytest.raises(SysExitCalled):

run_module("main")

main_patch.sys.exit.assert_called_once_with(0)


@pytest.mark.parametrize(
"expect_line",
["exitcode=0", "stdout<<DARKER_ACTION_EOF"],
)
def test_writes_github_output(main_patch, github_output, expect_line):
"""A successful run outputs a zero exit code and output from Darker."""
with pytest.raises(SysExitCalled):

run_module("main")

assert expect_line in github_output.read_text().splitlines()
Loading

0 comments on commit 925f271

Please sign in to comment.