Repository: VirtusLab/git-machete
Pull request #1224 (2024-04-19 21:08:42)

Release v3.25.1


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index e375ec7..c446781 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -184,7 +184,7 @@ jobs:
       - run: pip install tox
       # TODO (#1005): make zsh completion tests pass on macOS machine on CI
       - run: tox -e test-completions -- -vv -k "not zsh"
-      - run: PYTHON_VERSION=3.12-macos  tox -e coverage -- -vv
+      - run: PYTHON_VERSION=3-macos  tox -e coverage -- -vv
       - store_test_results:
           path: test-results/
       - persist_to_workspace:
@@ -196,11 +196,12 @@ jobs:
     steps:
       - checkout
       - run: pip install tox
-      # We don't collect coverage on Windows as it massively extends execution time for some reason.
-      # See https://github.com/tox-dev/tox/issues/3092 for why `py` and not `testenv`.
-      - run: tox -e py -- -vv
+      - run: PYTHON_VERSION=3-windows tox -e coverage -- -vv
       - store_test_results:
           path: test-results/
+      - persist_to_workspace:
+          root: .
+          paths: [ .coverage.* ]
 
   "coverage upload":
     executor: ubuntu_executor
@@ -222,9 +223,6 @@ jobs:
           name: '[Dry run] Deploy to PyPI'
           # Side effects: does an actual release, but to the test PyPI
           command: bash ci/pypi/ci-deploy.sh --dry-run
-      - run:
-          name: '[Dry run] Wait up to 30 minutes for PyPI package to be available'
-          command: bash ci/pypi/ci-wait-for-package.sh test.pypi.org 30
 
       - run:
           name: '[Dry run] Update Homebrew with local installation test'
@@ -361,6 +359,7 @@ workflows:
             branches:
               only:
                 - "develop"
+                - "/.*dry-run.*/"
                 - "/hotfix.*/"
                 - "master"
           requires:
diff --git a/.gitignore b/.gitignore
index d727e75..abb03fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,8 @@
 AUTHORS
 ChangeLog
 build/
-.coverage*
+.coverage
+.coverage.*
 coverage.xml
 dist/
 docs/html/
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 735b1cf..dfd6d6f 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,9 @@
 # Release notes
 
+## New in git-machete 3.25.1
+
+- fixed: `git machete git{hub,lab} restack-{pr,mr}` now first retargets, then pushes (so that certain CIs see the correct base branch in env vars)
+
 ## New in git-machete 3.25.0
 
 - added: GitLab support via `git machete gitlab` (first suggested by @mikeynap, partly contributed by @max-nicholson)
diff --git a/ci/homebrew/ci-deploy.sh b/ci/homebrew/ci-deploy.sh
index e321e35..fa995ee 100644
--- a/ci/homebrew/ci-deploy.sh
+++ b/ci/homebrew/ci-deploy.sh
@@ -12,20 +12,26 @@ NONINTERACTIVE=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebre
 eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
 brew --version
 
+version=$(cut -d\' -f2 git_machete/__init__.py)
+
+function pypi_metadata_json() {
+  curl -s "https://$pypi_host/pypi/git-machete/$version/json" | jq '.urls | map(select(.packagetype == "sdist")) | .[0]'
+}
+
 if [[ ${1-} == "--dry-run" || ${CIRCLE_BRANCH-} != "master" ]]; then
   do_push=false
   pypi_host=test.pypi.org
+  # For some reason, sometimes the package doesn't get advertised under .../packages/source/g/git-machete/... URL within a reasonable time.
+  url=$(pypi_metadata_json | jq --raw-output .url)
 else
   do_push=true
   pypi_host=pypi.org
+  # Do not use https://*files.pythonhosted.org/... URLs (the ones coming from the JSON above) for actual formula updates,
+  # see https://github.com/orgs/Homebrew/discussions/5193
+  url="https://$pypi_host/packages/source/g/git-machete/git-machete-$version.tar.gz"
 fi
 
-version=$(cut -d\' -f2 git_machete/__init__.py)
-# Do not use https://*files.pythonhosted.org/... URLs, see https://github.com/orgs/Homebrew/discussions/5193
-url="https://$pypi_host/packages/source/g/git-machete/git-machete-$version.tar.gz"
-sha256=$(
-  curl -s https://$pypi_host/pypi/git-machete/"$version"/json \
-  | jq --raw-output '.urls | map(select(.packagetype == "sdist")) | .[0].digests.sha256')
+sha256=$(pypi_metadata_json | jq --raw-output .digests.sha256)
 
 # We need to run `brew tap homebrew/core` manually because:
 # 1. the formula files need to be present at .../.linuxbrew/Homebrew/Library/Taps/... -
diff --git a/docs/man/git-machete.1 b/docs/man/git-machete.1
index 6359b2c..95e5542 100644
--- a/docs/man/git-machete.1
+++ b/docs/man/git-machete.1
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "GIT-MACHETE" "1" "Apr 14, 2024" "" "git-machete"
+.TH "GIT-MACHETE" "1" "Apr 19, 2024" "" "git-machete"
 .SH NAME
-git-machete \- git-machete 3.25.0
+git-machete \- git-machete 3.25.1
 .sp
 git machete is a robust tool that \fBsimplifies your git workflows\fP\&.
 .sp
@@ -1023,9 +1023,9 @@ Perform the following sequence of actions:
 .IP 1. 3
 If the PR for the current branch is ready for review, it gets converted to a draft.
 .IP 2. 3
-The branch is (force\-)pushed into remote.
-.IP 3. 3
 The PR is retargeted to its upstream (parent) branch, as in \fBretarget\-pr\fP\&.
+.IP 3. 3
+The branch is (force\-)pushed into remote.
 .IP 4. 3
 If the PR has been converted to draft in step 1, it\(aqs reverted to ready for review state.
 .UNINDENT
@@ -1251,9 +1251,9 @@ Perform the following sequence of actions:
 .IP 1. 3
 If the MR for the current branch is ready for review, it gets converted to a draft.
 .IP 2. 3
-The branch is (force\-)pushed into remote.
-.IP 3. 3
 The MR is retargeted to its upstream (parent) branch, as in \fBretarget\-mr\fP\&.
+.IP 3. 3
+The branch is (force\-)pushed into remote.
 .IP 4. 3
 If the MR has been converted to draft in step 1, it\(aqs reverted to ready for review state.
 .UNINDENT
diff --git a/docs/source/cli/github.rst b/docs/source/cli/github.rst
index 2b6a906..1276346 100644
--- a/docs/source/cli/github.rst
+++ b/docs/source/cli/github.rst
@@ -102,8 +102,8 @@ Creates, checks out and manages GitHub PRs while keeping them reflected in branc
     Perform the following sequence of actions:
 
     #. If the PR for the current branch is ready for review, it gets converted to a draft.
-    #. The branch is (force-)pushed into remote.
     #. The PR is retargeted to its upstream (parent) branch, as in ``retarget-pr``.
+    #. The branch is (force-)pushed into remote.
     #. If the PR has been converted to draft in step 1, it's reverted to ready for review state.
 
     The drafting/undrafting is useful in case the GitHub repository has set up `CODEOWNERS <https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners>`_.
diff --git a/docs/source/cli/gitlab.rst b/docs/source/cli/gitlab.rst
index 06ab95d..c6ef38c 100644
--- a/docs/source/cli/gitlab.rst
+++ b/docs/source/cli/gitlab.rst
@@ -103,8 +103,8 @@ Creates, checks out and manages GitLab MRs while keeping them reflected in branc
     Perform the following sequence of actions:
 
     #. If the MR for the current branch is ready for review, it gets converted to a draft.
-    #. The branch is (force-)pushed into remote.
     #. The MR is retargeted to its upstream (parent) branch, as in ``retarget-mr``.
+    #. The branch is (force-)pushed into remote.
     #. If the MR has been converted to draft in step 1, it's reverted to ready for review state.
 
     The drafting/undrafting is useful in case the GitLab project has set up `code owners <https://docs.gitlab.com/ee/user/project/codeowners/>`_.
diff --git a/git_machete/__init__.py b/git_machete/__init__.py
index 07824c0..35f0d3b 100644
--- a/git_machete/__init__.py
+++ b/git_machete/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '3.25.0'
+__version__ = '3.25.1'
diff --git a/git_machete/client.py b/git_machete/client.py
index 9fef5c3..33bd5a3 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -2268,6 +2268,9 @@ class MacheteClient:
                 if converted_to_draft:
                     print(f'{pr.display_text()} has been temporarily marked as draft')
 
+                # Note that retarget should happen BEFORE push, see issue #1222
+                self.retarget_pr(spec, head, ignore_if_missing=False)
+
                 if s == SyncToRemoteStatuses.AHEAD_OF_REMOTE:
                     assert remote is not None
                     self.__handle_ahead_state(
@@ -2303,8 +2306,6 @@ class MacheteClient:
                     opt_no_detect_squash_merges=False)
                 self.__print_new_line(False)
 
-                self.retarget_pr(spec, head, ignore_if_missing=False)
-
                 if converted_to_draft:
                     code_hosting_client.set_draft_status_of_pull_request(prs[0].number, target_draft_status=False)
                     print(f'{pr.display_text()} has been marked as ready for review again')
diff --git a/git_machete/generated_docs.py b/git_machete/generated_docs.py
index 153419e..77f1f06 100644
--- a/git_machete/generated_docs.py
+++ b/git_machete/generated_docs.py
@@ -616,10 +616,10 @@ long_docs: Dict[str, str] = {
 
                  * If the PR for the current branch is ready for review, it gets converted to a draft.
 
-                 * The branch is (force-)pushed into remote.
-
                  * The PR is retargeted to its upstream (parent) branch, as in `retarget-pr`.
 
+                 * The branch is (force-)pushed into remote.
+
                  * If the PR has been converted to draft in step 1, it's reverted to ready for review state.
 
               The drafting/undrafting is useful in case the GitHub repository has set up CODEOWNERS.
@@ -797,10 +797,10 @@ long_docs: Dict[str, str] = {
 
                  * If the MR for the current branch is ready for review, it gets converted to a draft.
 
-                 * The branch is (force-)pushed into remote.
-
                  * The MR is retargeted to its upstream (parent) branch, as in `retarget-mr`.
 
+                 * The branch is (force-)pushed into remote.
+
                  * If the MR has been converted to draft in step 1, it's reverted to ready for review state.
 
               The drafting/undrafting is useful in case the GitLab project has set up code owners.
diff --git a/requirements/coverage.txt b/requirements/coverage.txt
index 11574da..2a3d760 100644
--- a/requirements/coverage.txt
+++ b/requirements/coverage.txt
@@ -2,10 +2,6 @@ coverage==6.2; python_version <= '3.6'
 coverage==7.2.7; python_version >= '3.7' and python_version < '3.8'
 coverage==7.4.4; python_version >= '3.8'
 
-pytest==7.0.1; python_version <= '3.6'
-pytest==7.4.4; python_version >= '3.7' and python_version < '3.8'
-pytest==8.1.1; python_version >= '3.8'
-
-pytest-mock==3.6.1; python_version <= '3.6'
-pytest-mock==3.11.1; python_version >= '3.7' and python_version < '3.8'
-pytest-mock==3.14.0; python_version >= '3.8'
+pytest-cov==4.0.0; python_version <= '3.6'
+pytest-cov==4.1.0; python_version >= '3.7' and python_version < '3.8'
+pytest-cov==5.0.0; python_version >= '3.8'
diff --git a/requirements/mypy.txt b/requirements/mypy.txt
index ebbbcc6..47b10dc 100644
--- a/requirements/mypy.txt
+++ b/requirements/mypy.txt
@@ -1,11 +1,3 @@
 mypy==0.971; python_version <= '3.6'
 mypy==1.4.1; python_version >= '3.7' and python_version < '3.8'
 mypy==1.9.0; python_version >= '3.8'
-
-pytest==7.0.1; python_version <= '3.6'
-pytest==7.4.4; python_version >= '3.7' and python_version < '3.8'
-pytest==8.1.1; python_version >= '3.8'
-
-pytest-mock==3.6.1; python_version <= '3.6'
-pytest-mock==3.11.1; python_version >= '3.7' and python_version < '3.8'
-pytest-mock==3.14.0; python_version >= '3.8'
diff --git a/requirements/py-docs.txt b/requirements/py-docs.txt
index 8ecfdce..ea592d8 100644
--- a/requirements/py-docs.txt
+++ b/requirements/py-docs.txt
@@ -1,3 +1,3 @@
-docutils==0.20.1
+docutils==0.21.1
 pygments==2.17.2
 beautifulsoup4==4.12.3
diff --git a/requirements/pypi-deploy.txt b/requirements/pypi-deploy.txt
index 53e9d91..535d067 100644
--- a/requirements/pypi-deploy.txt
+++ b/requirements/pypi-deploy.txt
@@ -1,3 +1,3 @@
-setuptools==69.2.0
+setuptools==69.5.1
 twine==5.0.0
 wheel==0.43.0
diff --git a/requirements/typos.txt b/requirements/typos.txt
index d20e098..736d46b 100644
--- a/requirements/typos.txt
+++ b/requirements/typos.txt
@@ -1,1 +1,1 @@
-typos==1.20.4
+typos==1.20.8
diff --git a/setup.py b/setup.py
index 9a85122..acdaf4a 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ from git_machete import __version__
 this_directory = path.abspath(path.dirname(__file__))
 with open(path.join(this_directory, 'README.md'), mode="r", encoding="utf-8") as f:
     # PyPI webpage seems to be always served with white background, let's remove the GitHub-specific dark variants of images.
-    long_description = re.sub("^.*#gh-dark-mode-only.*$", "", f.read())
+    long_description = re.sub("(?m)^.*#gh-dark-mode-only.*\n", "", f.read())
 
 setup(
     name='git-machete',
diff --git a/tox.ini b/tox.ini
index 2b05813..3fed6e6 100644
--- a/tox.ini
+++ b/tox.ini
@@ -84,18 +84,16 @@ commands = {posargs}
 description = "Check the test coverage of the code"
 deps =
   -r{[requirements]dir}/coverage.txt
+  -r{[requirements]dir}/testenv.txt
 passenv = PYTHON_VERSION
 allowlist_externals = cp
 commands =
-  # Generates (or appends results to the existing) .coverage binary file (SQLite database),
-  # used as the source of truth for the subsequent reports.
-  # Note that coverage (as of v7.2.3) doesn't support parallel running (`--numprocesses=...`) via python-xdist.
-  coverage run --append --branch --omit='tests/*' \
-    -m pytest --junitxml=test-results/testenv-{envname}.xml -m "not completion_e2e" {posargs}
-  # Prints a report to console
-  coverage report
-  # Saves a report to htmlcov/
+  # Generate (or append results to the existing) .coverage binary file (SQLite database)
+  pytest --cov=git_machete --cov-append --cov-branch \
+    --numprocesses=auto --junitxml=test-results/testenv-{envname}.xml -m "not completion_e2e" {posargs}
+  # Save a report to htmlcov/
   coverage html --show-contexts
+  # Copy the coverage file so that it can be `coverage combine`d with other results
   cp .coverage .coverage.{env:PYTHON_VERSION:bin}
 
 [testenv:coverage-erase]
@@ -106,6 +104,7 @@ commands = coverage erase
 
 [coverage:run]
 dynamic_context = test_function
+omit = tests/*,git_machete/bin.py
 relative_files = True
 
 [coverage:report]
@@ -122,8 +121,11 @@ description = "Combine coverage results"
 deps =
   -r{[requirements]dir}/coverage.txt
 commands =
+  # Combine .coverage.* files into .coverage file
   coverage combine
-  # Saves a report to coverage.xml (uploaded to Codecov from CI, as Codecov apparently does not accept .coverage binary files)
+  # Print a report to console
+  coverage report
+  # Save a report to coverage.xml (uploaded to Codecov from CI, as Codecov apparently does not accept .coverage binary files)
   coverage xml
 
 # Python 3.11 is needed in envs that use Sphinx due to https://github.com/VirtusLab/git-machete/issues/936
@@ -175,6 +177,7 @@ commands =
 [testenv:mypy]
 deps =
   -r{[requirements]dir}/mypy.txt
+  -r{[requirements]dir}/testenv.txt
 commands =
   mypy --config-file mypy.ini git_machete tests
 


Test patch:
diff --git a/tests/test_github_restack_pr.py b/tests/test_github_restack_pr.py
index 3204512..bd1d9cb 100644
--- a/tests/test_github_restack_pr.py
+++ b/tests/test_github_restack_pr.py
@@ -108,13 +108,13 @@ class TestGitHubRestackPR(BaseTest):
         assert_success(
             ['github', 'restack-pr'],
             """
+            Base branch of PR #14 has been switched to master
             Pushing untracked branch feature_1 to origin...
 
               master (untracked)
               |
-              o-feature_1 *
+              o-feature_1 *  PR #14 (some_other_user)
 
-            Base branch of PR #14 has been switched to master
             """
         )
         pr = github_api_state.get_pull_by_number(14)
@@ -149,15 +149,15 @@ class TestGitHubRestackPR(BaseTest):
             ['github', 'restack-pr'],
             """
             PR #15 has been temporarily marked as draft
+            Base branch of PR #15 has been switched to master
+            Description of PR #15 has been updated
             Branch feature diverged from (and has newer commits than) its remote counterpart origin/feature.
             Pushing feature with force-with-lease to origin...
 
               master (untracked)
               |
-              o-feature *
+              o-feature *  PR #15 (some_other_user)
 
-            Base branch of PR #15 has been switched to master
-            Description of PR #15 has been updated
             PR #15 has been marked as ready for review again
             """
         )
@@ -192,14 +192,14 @@ class TestGitHubRestackPR(BaseTest):
             ['github', 'restack-pr'],
             """
             PR #15 has been temporarily marked as draft
+            Base branch of PR #15 has been switched to master
+            Description of PR #15 has been updated
             Pushing feature to origin...
 
               master (untracked)
               |
-              o-feature *
+              o-feature *  PR #15 (some_other_user)
 
-            Base branch of PR #15 has been switched to master
-            Description of PR #15 has been updated
             PR #15 has been marked as ready for review again
             """
         )
diff --git a/tests/test_gitlab_restack_mr.py b/tests/test_gitlab_restack_mr.py
index cb71581..0315295 100644
--- a/tests/test_gitlab_restack_mr.py
+++ b/tests/test_gitlab_restack_mr.py
@@ -108,13 +108,13 @@ class TestGitLabRestackMR(BaseTest):
         assert_success(
             ['gitlab', 'restack-mr'],
             """
+            Target branch of MR !14 has been switched to master
             Pushing untracked branch feature_1 to origin...
 
               master (untracked)
               |
-              o-feature_1 *
+              o-feature_1 *  MR !14 (some_other_user)
 
-            Target branch of MR !14 has been switched to master
             """
         )
         mr = gitlab_api_state.get_pull_by_number(14)
@@ -152,15 +152,15 @@ class TestGitLabRestackMR(BaseTest):
             ['gitlab', 'restack-mr'],
             """
             MR !15 has been temporarily marked as draft
+            Target branch of MR !15 has been switched to master
+            Description of MR !15 has been updated
             Branch feature diverged from (and has newer commits than) its remote counterpart origin/feature.
             Pushing feature with force-with-lease to origin...
 
               master (untracked)
               |
-              o-feature *
+              o-feature *  MR !15 (some_other_user)
 
-            Target branch of MR !15 has been switched to master
-            Description of MR !15 has been updated
             MR !15 has been marked as ready for review again
             """
         )
@@ -196,14 +196,14 @@ class TestGitLabRestackMR(BaseTest):
             ['gitlab', 'restack-mr'],
             """
             MR !15 has been temporarily marked as draft
+            Target branch of MR !15 has been switched to master
+            Description of MR !15 has been updated
             Pushing feature to origin...
 
               master (untracked)
               |
-              o-feature *
+              o-feature *  MR !15 (some_other_user)
 
-            Target branch of MR !15 has been switched to master
-            Description of MR !15 has been updated
             MR !15 has been marked as ready for review again
             """
         )