Skip to content
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

CI test against Black master, release process to guard against compatibliity breakage #430

Merged
merged 6 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/test-future.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,57 @@ jobs:
- name: Test with pytest
run: |
pytest
- name: Note a possible Black incompatibility and required actions
if: failure()
shell: python
run: |
import json
import os
import urllib.request
from distutils.version import LooseVersion
from importlib.metadata import version
from textwrap import dedent

for linenum, line in enumerate(open("setup.cfg"), 1):
constraint = line.strip()
if constraint.startswith("black>="):
column = line.index("black>=") + 1
end_column = len(line)
break
else:
raise RuntimeError("black>= line not found in setup.cfg")

response = urllib.request.urlopen(
'https://pypi.org/pypi/black/json'
).read().decode()
latest_version = max(
LooseVersion(s)
for s in json.loads(response)['releases'].keys()
)

print(
dedent(
f"""
### :x: Future Black incompatibility? :x:

You could add a maximum version constraint for Black on
`setup.cfg` line {linenum}, e.g.
`{constraint},<={latest_version}`

See [#382](/akaihola/darker/issues/382)
for more information
"""
),
file=open(os.getenv("GITHUB_STEP_SUMMARY"), "a"),
)

print(
"::notice "
"file=setup.cfg,"
f"line={linenum},"
f"col={column},"
f"endColumn={end_column},"
"title=Future Black incompatibility?::"
"You could add a maximum version constraint for Black here, "
f"e.g. {constraint},<={latest_version}"
)
70 changes: 65 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,20 @@ in Black documentation, or the article
How?
====

To install, use::
To install or upgrade, use::

pip install darker
pip install --upgrade darker~=1.6.0

Or, if you're using Conda_ for package management::

conda install -c conda-forge darker isort
conda install -c conda-forge darker~=1.6.0 isort
conda update -c conda-forge darker
akaihola marked this conversation as resolved.
Show resolved Hide resolved

..

**Note:** It is recommended to use the '``~=``' "`compatible release`_" version
specifier for Darker. See `Guarding against Black compatibility breakage`_ for more
information.

The ``darker <myfile.py>`` or ``darker <directory>`` command
reads the original file(s),
Expand Down Expand Up @@ -571,9 +578,10 @@ do the following:
hooks:
- id: darker

4. install the Git hook scripts::
4. install the Git hook scripts and update to the newest version::

pre-commit install
pre-commit autoupdate
akaihola marked this conversation as resolved.
Show resolved Hide resolved

.. _pre-commit: https://pre-commit.com/
.. _pre-commit Installation: https://pre-commit.com/#installation
Expand Down Expand Up @@ -632,7 +640,7 @@ Create a file named ``.github/workflows/darker.yml`` inside your repository with
options: "--check --diff --color"
revision: "master..."
src: "./src"
version: "1.6.0"
version: "~=1.6.0"
akaihola marked this conversation as resolved.
Show resolved Hide resolved
lint: "flake8,pylint==2.13.1"

There needs to be a working Python environment, set up using ``actions/setup-python``
Expand Down Expand Up @@ -758,6 +766,58 @@ line options always take highest precedence.
.. _Pygments: https://pypi.org/project/Pygments/


Guarding against Black compatibility breakage
=============================================

Darker accesses some Black internals which don't belong to its public API. Darker is
thus subject to becoming incompatible with future versions of Black.

To protect users against such breakage, we test Darker daily against the `Black main
branch`_ and strive to proactively fix any potential incompatibilities through this
process. If a commit to Black ``main`` branch introduces an incompatibility with
Darker, we will release a first patch version for Darker that prevents upgrading Black
and a second patch version that fixes the incompatibility. A hypothetical example:

1. Darker 9.0.0; Black 35.12.0
-> OK
2. Darker 9.0.0; Black ``main`` (after 35.12.0)
-> ERROR on CI test-future_ workflow
3. Darker 9.0.1 released, with constraint ``Black<=35.12.0``
-> OK
4. Black 36.1.0 released, but Darker 9.0.1 prevents upgrade; Black 35.12.0
-> OK
5. Darker 9.0.2 released with a compatibility fix, constraint removed; Black 36.1.0
-> OK

If a Black release introduces an incompatibility before the second Darker patch version
that fixes it, the first Darker patch version will downgrade Black to the latest
compatible version:

1. Darker 9.0.0; Black 35.12.0
-> OK
2. Darker 9.0.0; Black 36.1.0
-> ERROR
3. Darker 9.0.1, constraint ``Black<=35.12.0``; downgrades to Black 35.12.0
-> OK
4. Darker 9.0.2 released with a compatibility fix, constraint removed; Black 36.1.0
-> OK

To be completely safe, you can pin both Darker and Black to known good versions, but
this may prevent you from receiving improvements in Black.

It is recommended to use the '``~=``' "`compatible release`_" version specifier for
Darker to ensure you have the latest version before the next major release that may
cause compatibility issues.

See issue `#382`_ and PR `#430`_ for more information.

.. _compatible release: https://peps.python.org/pep-0440/#compatible-release
.. _Black main branch: https://github.com/psf/black/commits/main
.. _test-future: https://github.com/akaihola/darker/blob/master/.github/workflows/test-future.yml
.. _#382: https://github.com/akaihola/darker/issues/382
.. _#430: https://github.com/akaihola/darker/issues/430


How does it work?
=================

Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ inputs:
required: false
default: "."
version:
description: 'Python Version specifier (PEP440) - e.g. "1.6.0"'
description: 'Version of Darker to use, e.g. "~=1.6.0", "1.6.0", "@master"'
required: false
default: "1.6.0"
default: "~=1.6.0"
revision:
description: >-
Git revision range to compare when determining modified lines.
Expand Down
2 changes: 2 additions & 0 deletions action/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
if VERSION:
if VERSION.startswith("@"):
req[0] = f"git+https://github.com/akaihola/darker{VERSION}#egg={req[0]}"
elif VERSION.startswith(("~", "=", "<", ">")):
req[1] += VERSION
akaihola marked this conversation as resolved.
Show resolved Hide resolved
else:
req[0] += f"=={VERSION}"
linter_options = []
Expand Down
14 changes: 10 additions & 4 deletions release_tools/bump_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,26 @@
VERSION_PY_PATH: {r"^__version__ *= *\"{old_version->new_version}\""},
"action.yml": {
(
r"^ description: \'Python Version specifier \(PEP440\) - e\.g\."
r' "{old_version->new_version}"'
r"^ description: \'Version of Darker to use, e\.g\."
r' "~={old_version->new_version}"'
),
r'^ default: "{old_version->new_version}"',
(
r"^ description: \'Version of Darker to use, e\.g\."
r' "~=.*?", "{old_version->new_version}"'
),
r'^ default: "~={old_version->new_version}"',
(
r"^ uses: akaihola/darker/.github/actions/commit-range"
r"@{old_version->new_version}"
),
},
"README.rst": {
r"^ pip install --upgrade darker~={old_version->new_version}",
r"^ conda install -c conda-forge darker~={old_version->new_version} isort",
r"^ rev: {old_version->new_version}",
r"^ rev: {old_version->new_version}",
r"^ - uses: akaihola/darker@{old_version->new_version}",
r'^ version: "{old_version->new_version}"',
r'^ version: "~={old_version->new_version}"',
r"label=release%20{any_version->next_version}",
(
r"^\.\. \|next-milestone\| image::"
Expand Down