From 0675ca9d4be5a05e44efd6ab69e56c13c46f425c Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sun, 25 Dec 2022 23:37:08 +0200 Subject: [PATCH 1/6] Support `~=` "compatible release" in GH action --- action/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/action/main.py b/action/main.py index 97850da6a..ee7c17821 100644 --- a/action/main.py +++ b/action/main.py @@ -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 else: req[0] += f"=={VERSION}" linter_options = [] From 78ef27ee849eb1277b2d383899afd07ca9860261 Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sun, 25 Dec 2022 23:37:42 +0200 Subject: [PATCH 2/6] Use `darker~=1.6.0` as default for GH action --- action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 031602781..d5abdec10 100644 --- a/action.yml +++ b/action.yml @@ -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. From 45817810ac103961e12d7ff840007c5f9c38b43d Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sun, 25 Dec 2022 23:38:06 +0200 Subject: [PATCH 3/6] Document usage of `~=` "compatible release" --- README.rst | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 9830e2251..1372e8b0c 100644 --- a/README.rst +++ b/README.rst @@ -128,13 +128,33 @@ 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 + +.. + + **Note:** 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. If an update to Black introduces an + incompatibility with Darker, we will release a first point release for Darker that + prevents upgrading Black and a second point release that fixes the incompatibility. + + We test Darker daily against the `Black main branch`_ and strive to proactively + fix any potential incompatibilities through this process. If a Black release + introduces an incompatibility before the second Darker point release that fixes it, + the first Darker point release will downgrade Black to the latest compatible + version. + + 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. + + See issue `#382`_ for more information. The ``darker `` or ``darker `` command reads the original file(s), @@ -159,6 +179,9 @@ You can enable additional features with command line options: .. _Conda: https://conda.io/ .. _conda-forge: https://conda-forge.org/ +.. _compatible release: https://peps.python.org/pep-0440/#compatible-release +.. _Black main branch: https://github.com/psf/black/commits/main +.. _#382: https://github.com/akaihola/darker/issues/382 Example @@ -571,9 +594,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 .. _pre-commit: https://pre-commit.com/ .. _pre-commit Installation: https://pre-commit.com/#installation @@ -632,7 +656,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" lint: "flake8,pylint==2.13.1" There needs to be a working Python environment, set up using ``actions/setup-python`` From 2034f11c5d29b244636e4da0e02dbd6df0ff23cc Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sun, 25 Dec 2022 23:45:41 +0200 Subject: [PATCH 4/6] Fix `bump_version.py` to find new version strings --- release_tools/bump_version.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/release_tools/bump_version.py b/release_tools/bump_version.py index 4f17dc0e4..5b05907fb 100644 --- a/release_tools/bump_version.py +++ b/release_tools/bump_version.py @@ -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::" From f14a59ff30fe427cf6d88a40d43cbad185639c8f Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Sun, 25 Dec 2022 23:58:39 +0200 Subject: [PATCH 5/6] Add job summary and `setup.cfg` annotation on Black breakage --- .github/workflows/test-future.yml | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/test-future.yml b/.github/workflows/test-future.yml index 9b24c7766..032c44a32 100644 --- a/.github/workflows/test-future.yml +++ b/.github/workflows/test-future.yml @@ -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}" + ) From f8ed7ac5ac6e1a93fdfe6b936b2ce5d30467ffec Mon Sep 17 00:00:00 2001 From: Antti Kaihola <13725+akaihola@users.noreply.github.com> Date: Mon, 26 Dec 2022 21:36:35 +0200 Subject: [PATCH 6/6] Move incompatibility guard docs to its own section --- README.rst | 72 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index 1372e8b0c..4ba9a6b50 100644 --- a/README.rst +++ b/README.rst @@ -140,21 +140,8 @@ Or, if you're using Conda_ for package management:: .. **Note:** 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. If an update to Black introduces an - incompatibility with Darker, we will release a first point release for Darker that - prevents upgrading Black and a second point release that fixes the incompatibility. - - We test Darker daily against the `Black main branch`_ and strive to proactively - fix any potential incompatibilities through this process. If a Black release - introduces an incompatibility before the second Darker point release that fixes it, - the first Darker point release will downgrade Black to the latest compatible - version. - - 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. - - See issue `#382`_ for more information. + specifier for Darker. See `Guarding against Black compatibility breakage`_ for more + information. The ``darker `` or ``darker `` command reads the original file(s), @@ -179,9 +166,6 @@ You can enable additional features with command line options: .. _Conda: https://conda.io/ .. _conda-forge: https://conda-forge.org/ -.. _compatible release: https://peps.python.org/pep-0440/#compatible-release -.. _Black main branch: https://github.com/psf/black/commits/main -.. _#382: https://github.com/akaihola/darker/issues/382 Example @@ -782,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? =================