Skip to content
Open
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
2 changes: 2 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## New in git-machete 3.45.1

- added: `advice.macheteCreateFromFork` git config key suppresses the fork warning in `github create-pr` and `gitlab create-mr` when set to `false`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks okay! pls rebase & resolve the conflict


## New in git-machete 3.45.0

- added: `GIT_MACHETE_PUSH_OPTS` environment variable forwards arbitrary extra options to every `git push` invocation (contributed by @HWiese1980)
Expand Down
12 changes: 12 additions & 0 deletions docs/man/git-machete.1

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions docs/source/cli/github.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ Create, check out and manage GitHub PRs while keeping them reflected in branch l

**Git config keys**

``advice.macheteCreateFromFork`` (``create-pr`` only)
.. include:: git-config-keys/advice.macheteCreateFromFork.rst

``machete.github.{domain,remote,organization,repository,baseRemote,baseOrganization,baseRepository}`` (all subcommands)
.. include:: git-config-keys/github.access.rst

Expand Down
3 changes: 3 additions & 0 deletions docs/source/cli/gitlab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ Create, check out and manage GitLab MRs while keeping them reflected in branch l

**Git config keys**

``advice.macheteCreateFromFork`` (``create-mr`` only)
.. include:: git-config-keys/advice.macheteCreateFromFork.rst

``machete.gitlab.{domain,remote,namespace,project,baseRemote,baseNamespace,baseProject}`` (all subcommands)
.. include:: git-config-keys/gitlab.access.rst

Expand Down
4 changes: 4 additions & 0 deletions docs/source/git-config-keys/advice.macheteCreateFromFork.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Controls the warning shown when creating a pull/merge request whose base and head branches live in different repositories.
Set to ``false`` to suppress the warning about creating stacked pull/merge requests from forks; enabled by default.
This setting affects only the warning, not repository selection or request creation.
For example, run ``git config advice.macheteCreateFromFork false`` in a repository, or add ``--global`` to apply it everywhere.
2 changes: 1 addition & 1 deletion git_machete/client/with_code_hosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def create_pull_request(

base_org_repo = base_org_repo_remote.extract_org_and_repo()
head_org_repo = head_org_repo_remote.extract_org_and_repo()
if base_org_repo != head_org_repo:
if base_org_repo != head_org_repo and self._config.advice_machete_create_from_fork():
warn(f"{spec.base_branch_name} branch <b>{base}</b> lives in <b>{base_org_repo}</b> {spec.repository_name},\n"
f"while {spec.head_branch_name} branch <b>{head}</b> lives in <b>{head_org_repo}</b> {spec.repository_name}.\n"
f"git-machete will now attempt to create {spec.pr_short_name_article} {spec.pr_short_name} in <b>{base_org_repo}</b>.\n"
Expand Down
4 changes: 4 additions & 0 deletions git_machete/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class PRDescriptionIntroStyle(ParsableEnum):

class MacheteConfig:

_ADVICE_MACHETE_CREATE_FROM_FORK = 'advice.macheteCreateFromFork'
_ADVICE_MACHETE_EDITOR_SELECTION = 'advice.macheteEditorSelection'
_SQUASH_MERGE_DETECTION = 'machete.squashMergeDetection'
_STATUS_EXTRA_SPACE_BEFORE_BRANCH_NAME = 'machete.status.extraSpaceBeforeBranchName'
Expand All @@ -61,6 +62,9 @@ def __init__(self, git: Optional[Git] = None) -> None:
def advice_machete_editor_selection(self) -> bool:
return self._git.get_config_attr_or_none(self._ADVICE_MACHETE_EDITOR_SELECTION) != 'false'

def advice_machete_create_from_fork(self) -> bool:
return self._git.get_config_attr_or_none(self._ADVICE_MACHETE_CREATE_FROM_FORK) != 'false'

def core_editor(self) -> Optional[str]:
return self._git.get_config_attr_or_none("core.editor")

Expand Down
12 changes: 12 additions & 0 deletions git_machete/generated_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,12 @@

<b>Git config keys</b>

`advice.macheteCreateFromFork` (`create-pr` only)
Controls the warning shown when creating a pull/merge request whose base and head branches live in different repositories.
Set to `false` to suppress the warning about creating stacked pull/merge requests from forks; enabled by default.
This setting affects only the warning, not repository selection or request creation.
For example, run `git config advice.macheteCreateFromFork false` in a repository, or add `--global` to apply it everywhere.

`machete.github.{domain,remote,organization,repository,baseRemote,baseOrganization,baseRepository}` (all subcommands)
`machete.github.domain`
The domain of the GitHub API server, for use with GitHub Enterprise; otherwise inferred from the remote URL.
Expand Down Expand Up @@ -1069,6 +1075,12 @@

<b>Git config keys</b>

`advice.macheteCreateFromFork` (`create-mr` only)
Controls the warning shown when creating a pull/merge request whose base and head branches live in different repositories.
Set to `false` to suppress the warning about creating stacked pull/merge requests from forks; enabled by default.
This setting affects only the warning, not repository selection or request creation.
For example, run `git config advice.macheteCreateFromFork false` in a repository, or add `--global` to apply it everywhere.

`machete.gitlab.{domain,remote,namespace,project,baseRemote,baseNamespace,baseProject}` (all subcommands)
`machete.gitlab.domain`
The domain of the GitLab API server, for use with a GitLab self-managed instance; otherwise inferred from the remote URL.
Expand Down
57 changes: 57 additions & 0 deletions tests/test_fork_advice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from typing import Optional

import pytest
from pytest_mock import MockerFixture

from tests import mockers_github, mockers_gitlab
from tests.base_test import BaseTest
from tests.cli_runner import assert_success, rewrite_branch_layout_file
from tests.git_repository import add_remote, commit, create_repo, create_repo_with_remote, new_branch, push, set_git_config_key
from tests.mockers_code_hosting import mock_from_url


class TestForkAdvice(BaseTest):

@pytest.mark.parametrize('provider', ['github', 'gitlab'])
@pytest.mark.parametrize('advice', [None, 'true', 'false'])
def test_create_from_fork(self, mocker: MockerFixture, provider: str, advice: Optional[str]) -> None:
self.patch_symbol(mocker, 'git_machete.code_hosting.OrganizationAndRepository.from_url', mock_from_url)
if provider == 'github':
self.patch_symbol(mocker, 'git_machete.github.GitHubToken.for_domain', mockers_github.mock_github_token_for_domain_none)
self.patch_symbol(mocker, 'urllib.request.urlopen', mockers_github.mock_urlopen(mockers_github.MockGitHubAPIState.with_prs()))
display, short, base_label, head_label, repository = 'GitHub', 'PR', 'base', 'head', 'repository'
else:
self.patch_symbol(mocker, 'git_machete.gitlab.GitLabToken.for_domain', mockers_gitlab.mock_gitlab_token_for_domain_none)
self.patch_symbol(mocker, 'urllib.request.urlopen', mockers_gitlab.mock_urlopen(mockers_gitlab.MockGitLabAPIState.with_mrs()))
display, short, base_label, head_label, repository = 'GitLab', 'MR', 'target', 'source', 'project'
article = 'a' if provider == 'github' else 'an'
create_repo_with_remote()
fork_path = create_repo('remote-1', bare=True, switch_dir_to_new_repo=False)
add_remote('fork', fork_path)
new_branch('master')
commit()
push(remote='fork', set_upstream=False)
push(remote='origin')
new_branch('feature')
commit()
push(remote='origin')
rewrite_branch_layout_file('master\n\tfeature')
set_git_config_key(f'machete.{provider}.baseRemote', 'fork')
if advice is not None:
set_git_config_key('advice.macheteCreateFromFork', advice)
warning = f"""
Warn: {base_label} branch master lives in example-org/example-repo-1 {repository},
while {head_label} branch feature lives in example-org/example-repo {repository}.
git-machete will now attempt to create {article} {short} in example-org/example-repo-1.

Note that due to the limitations of {display}'s {short} model, it is not possible to cleanly create stacked {short}s from forks.
For example, in a hypothetical chain some-other-branch -> feature -> master, {article} {short} from some-other-branch to feature
could not be created in example-org/example-repo-1, since its {head_label} branch feature lives in example-org/example-repo.
Generally, {short}s need to be created in whatever {repository} the {base_label} branch lives.
""" if advice != 'false' else ''
expected = warning + f"""
Checking if {head_label} branch feature exists in origin remote... YES
Checking if {base_label} branch master exists in fork remote... YES
Creating {article} {short} from feature to master... OK, see www.{provider}.com
"""
assert_success([provider, f'create-{short.lower()}'], expected)