1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-15 03:20:10 +01:00

checkupdates: make merge-request per appid on push

This commit is contained in:
Hans-Christoph Steiner 2022-06-29 12:31:28 +02:00 committed by linsui
parent 66a340fe89
commit 9a34590e95
2 changed files with 111 additions and 38 deletions

View File

@ -685,7 +685,22 @@ def get_last_build_from_app(app: metadata.App) -> metadata.Build:
def push_commits(remote_name='origin', verbose=False): def push_commits(remote_name='origin', verbose=False):
"""Push commits using either appid or 'checkupdates' as branch name.""" """Make git branch then push commits as merge request.
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
name. This is to support the old way operating, e.g. in batches.
This uses GitLab "Push Options" to create a merge request. Git
Push Options are config data that can be sent via `git push
--push-option=... origin foo`.
References
----------
* https://docs.gitlab.com/ee/user/project/push_options.html
"""
git_repo = git.Repo.init('.') git_repo = git.Repo.init('.')
files = set() files = set()
upstream_main = 'main' if 'main' in git_repo.remotes.upstream.refs else 'master' upstream_main = 'main' if 'main' in git_repo.remotes.upstream.refs else 'master'
@ -699,26 +714,40 @@ def push_commits(remote_name='origin', verbose=False):
m = re.match(r'metadata/([^\s]+)\.yml', files[0]) m = re.match(r'metadata/([^\s]+)\.yml', files[0])
if m: if m:
branch_name = m.group(1) # appid branch_name = m.group(1) # appid
if len(files) > 0: if not files:
return
progress = None
if verbose: if verbose:
from clint.textui import progress import clint.textui
bar = progress.Bar() progress_bar = clint.textui.progress.Bar()
class MyProgressPrinter(git.RemoteProgress): class MyProgressPrinter(git.RemoteProgress):
def update(self, op_code, current, maximum=None, message=None): def update(self, op_code, current, maximum=None, message=None):
if isinstance(maximum, float): if isinstance(maximum, float):
bar.show(current, maximum) progress_bar.show(current, maximum)
progress = MyProgressPrinter() progress = MyProgressPrinter()
else:
progress = None
git_repo.create_head(branch_name, force=True) git_repo.create_head(branch_name, force=True)
remote = git_repo.remotes[remote_name] remote = git_repo.remotes[remote_name]
pushinfos = remote.push( pushinfos = remote.push(
branch_name, force=True, set_upstream=True, progress=progress branch_name, force=True, set_upstream=True, progress=progress
) )
pushinfos = remote.push(
branch_name,
progress=progress,
force=True,
set_upstream=True,
push_option=[
'merge_request.create',
'merge_request.remove_source_branch',
'merge_request.title=' + 'bot: checkupdates for ' + branch_name,
'merge_request.description='
+ 'checkupdates-bot run %s' % os.getenv('CI_JOB_URL'),
],
)
for pushinfo in pushinfos: for pushinfo in pushinfos:
if pushinfo.flags & ( if pushinfo.flags & (
git.remote.PushInfo.ERROR git.remote.PushInfo.ERROR
@ -792,6 +821,8 @@ def main():
help=_("Only process apps with auto-updates")) help=_("Only process apps with auto-updates"))
parser.add_argument("--commit", action="store_true", default=False, parser.add_argument("--commit", action="store_true", default=False,
help=_("Commit changes")) help=_("Commit changes"))
parser.add_argument("--merge-request", action="store_true", default=False,
help=_("Commit changes, push, then make a merge request"))
parser.add_argument("--allow-dirty", action="store_true", default=False, parser.add_argument("--allow-dirty", action="store_true", default=False,
help=_("Run on git repo that has uncommitted changes")) help=_("Run on git repo that has uncommitted changes"))
metadata.add_metadata_arguments(parser) metadata.add_metadata_arguments(parser)
@ -806,6 +837,10 @@ def main():
logging.error(_('Build metadata git repo has uncommited changes!')) logging.error(_('Build metadata git repo has uncommited changes!'))
sys.exit(1) sys.exit(1)
if options.merge_request and not (options.appid and len(options.appid) == 1):
logging.error(_('--merge-request only runs on a single appid!'))
sys.exit(1)
apps = common.read_app_args(options.appid) apps = common.read_app_args(options.appid)
processed = [] processed = []
@ -821,7 +856,7 @@ def main():
logging.info(msg) logging.info(msg)
try: try:
checkupdates_app(app, options.auto, options.commit) checkupdates_app(app, options.auto, options.commit or options.merge_request)
processed.append(appid) processed.append(appid)
except Exception as e: except Exception as e:
msg = _("...checkupdate failed for {appid} : {error}").format(appid=appid, error=e) msg = _("...checkupdate failed for {appid} : {error}").format(appid=appid, error=e)
@ -830,6 +865,10 @@ def main():
failed[appid] = str(e) failed[appid] = str(e)
exit_code = 1 exit_code = 1
if options.appid and options.merge_request:
push_commits(verbose=options.verbose)
prune_empty_appid_branches()
status_update_json(processed, failed) status_update_json(processed, failed)
sys.exit(exit_code) sys.exit(exit_code)

View File

@ -339,9 +339,14 @@ class CheckupdatesTest(unittest.TestCase):
git_remote_upstream = os.path.join(testdir, 'git_remote_upstream') git_remote_upstream = os.path.join(testdir, 'git_remote_upstream')
upstream_repo = git.Repo.init(git_remote_upstream, bare=True) upstream_repo = git.Repo.init(git_remote_upstream, bare=True)
with upstream_repo.config_writer() as cw:
cw.set_value('receive', 'advertisePushOptions', True)
git_repo.create_remote('upstream', 'file://' + git_remote_upstream) git_repo.create_remote('upstream', 'file://' + git_remote_upstream)
git_remote_origin = os.path.join(testdir, 'git_remote_origin') git_remote_origin = os.path.join(testdir, 'git_remote_origin')
origin_repo = git.Repo.init(git_remote_origin, bare=True) origin_repo = git.Repo.init(git_remote_origin, bare=True)
with origin_repo.config_writer() as cw:
cw.set_value('receive', 'advertisePushOptions', True)
git_repo.create_remote('origin', 'file://' + git_remote_origin) git_repo.create_remote('origin', 'file://' + git_remote_origin)
return git_repo, origin_repo, upstream_repo return git_repo, origin_repo, upstream_repo
@ -425,9 +430,38 @@ class CheckupdatesTest(unittest.TestCase):
self.assertNotIn(appid, git_repo.remotes.origin.refs) self.assertNotIn(appid, git_repo.remotes.origin.refs)
self.assertNotIn(appid, git_repo.remotes.upstream.refs) self.assertNotIn(appid, git_repo.remotes.upstream.refs)
def test_make_merge_request(self): @mock.patch('sys.exit')
testdir = self.testdir.name @mock.patch('fdroidserver.metadata.read_metadata')
os.chdir(testdir) def test_merge_requests_flag(self, read_metadata, sys_exit):
def _sys_exit(return_code=0):
assert return_code != 0
raise fdroidserver.exception.FDroidException('sys.exit() ran')
def _read_metadata(a=None, b=None):
raise StopIteration('read_metadata() ran, test is successful')
appid = 'com.example'
# read_metadata.return_value = dict() # {appid: dict()}
read_metadata.side_effect = _read_metadata
sys_exit.side_effect = _sys_exit
# set up clean git repo
os.chdir(self.testdir.name)
git_repo = git.Repo.init()
open('foo', 'w').close()
git_repo.git.add(all=True)
git_repo.index.commit("all files")
with mock.patch('sys.argv', ['fdroid checkupdates', '--merge-request']):
with self.assertRaises(fdroidserver.exception.FDroidException):
fdroidserver.checkupdates.main()
sys_exit.assert_called()
sys_exit.reset_mock()
with mock.patch('sys.argv', ['fdroid checkupdates', '--merge-request', appid]):
with self.assertRaises(StopIteration):
fdroidserver.checkupdates.main()
sys_exit.assert_not_called()
if __name__ == "__main__": if __name__ == "__main__":