diff --git a/fdroidserver/checkupdates.py b/fdroidserver/checkupdates.py index d9ad8048..bd97135d 100644 --- a/fdroidserver/checkupdates.py +++ b/fdroidserver/checkupdates.py @@ -740,9 +740,22 @@ def checkout_appid_branch(appid): return True -def push_commits(remote_name='origin', branch_name='checkupdates', verbose=False): +def get_changes_versus_ref(git_repo, ref, f): + changes = [] + for m in re.findall( + r"^[+-].*", git_repo.git.diff(f"{ref}", '--', f), flags=re.MULTILINE + ): + if not re.match(r"^(\+\+\+|---) ", m): + changes.append(m) + return changes + + +def push_commits(branch_name='checkupdates', verbose=False): """Make git branch then push commits as merge request. + The appid is parsed from the actual file that was changed so that + only the right branch is ever updated. + This uses the appid as the standard branch name so that there is only ever one open merge request per-app. If multiple apps are included in the branch, then 'checkupdates' is used as branch @@ -760,9 +773,7 @@ def push_commits(remote_name='origin', branch_name='checkupdates', verbose=False git_repo = git.Repo.init('.') upstream_main = get_upstream_main_branch(git_repo) files = set() - for commit in git_repo.iter_commits( - f'{upstream_main}...HEAD', right_only=True - ): + for commit in git_repo.iter_commits(f'{upstream_main}...HEAD', right_only=True): files.update(commit.stats.files.keys()) files = list(files) @@ -773,6 +784,11 @@ def push_commits(remote_name='origin', branch_name='checkupdates', verbose=False if not files: return + remote = git_repo.remotes.origin + if branch_name in remote.refs: + if not get_changes_versus_ref(git_repo, f'origin/{branch_name}', files[0]): + return + git_repo.create_head(branch_name, force=True) push_options = [ 'merge_request.create', @@ -784,13 +800,7 @@ def push_commits(remote_name='origin', branch_name='checkupdates', verbose=False # mark as draft if there are only changes to CurrentVersion: current_version_only = True - for m in re.findall( - r"^[+-].*", - git_repo.git.diff(f"{upstream_main}...HEAD"), - flags=re.MULTILINE, - ): - if re.match(r"^(\+\+\+|---) ", m): - continue + for m in get_changes_versus_ref(git_repo, upstream_main, files[0]): if not re.match(r"^[-+]CurrentVersion", m): current_version_only = False break @@ -810,7 +820,6 @@ def push_commits(remote_name='origin', branch_name='checkupdates', verbose=False progress = MyProgressPrinter() - remote = git_repo.remotes[remote_name] pushinfos = remote.push( branch_name, progress=progress, diff --git a/tests/test_checkupdates.py b/tests/test_checkupdates.py index 2e802741..87420d2b 100755 --- a/tests/test_checkupdates.py +++ b/tests/test_checkupdates.py @@ -324,6 +324,9 @@ class CheckupdatesTest(unittest.TestCase): for f in (basedir / 'metadata').glob('*.yml'): shutil.copy(f, 'metadata') git_repo = git.Repo.init(testdir) + with git_repo.config_writer() as cw: + cw.set_value('user', 'name', 'Foo Bar') + cw.set_value('user', 'email', 'foo@bar.com') git_repo.git.add(all=True) git_repo.index.commit("all metadata files") @@ -341,6 +344,40 @@ class CheckupdatesTest(unittest.TestCase): return git_repo, origin_repo, upstream_repo + def test_get_changes_versus_ref(self): + def _make_commit_new_app(git_repo, metadata_file): + app = fdroidserver.metadata.App() + fdroidserver.metadata.write_metadata(metadata_file, app) + git_repo.git.add(metadata_file) + git_repo.git.commit(metadata_file, message=f'changed {metadata_file}') + + git_repo, origin_repo, upstream_repo = self._get_test_git_repos() + for remote in git_repo.remotes: + remote.push(git_repo.active_branch) + appid = 'com.testvalue' + metadata_file = f'metadata/{appid}.yml' + + # set up remote branch with change to app + git_repo.git.checkout('-b', appid) + _make_commit_new_app(git_repo, metadata_file) + git_repo.remotes.origin.push(appid) + + # reset local branch and there should be differences + upstream_main = fdroidserver.checkupdates.get_upstream_main_branch(git_repo) + git_repo.git.reset(upstream_main) + self.assertTrue( + fdroidserver.checkupdates.get_changes_versus_ref( + git_repo, f'origin/{appid}', metadata_file + ) + ) + # make new commit that matches the previous, different commit, no diff + _make_commit_new_app(git_repo, metadata_file) + self.assertFalse( + fdroidserver.checkupdates.get_changes_versus_ref( + git_repo, f'origin/{appid}', metadata_file + ) + ) + def test_push_commits(self): git_repo, origin_repo, upstream_repo = self._get_test_git_repos() for remote in git_repo.remotes: