def test_updater_main(tmpdir, upstream_repo, midstream_repo, git_at, monkeypatch, gerrit_push_map, run_click_command, call_with_env): monkeypatch.chdir(tmpdir) # we need to mock this because the tool is actually designed to work with # Gerrit but in the test we don't have an actual Gerrit server mock_check_if_similar_patch_pushed = MagicMock(return_value=False) monkeypatch.setattr('stdci_tools.pusher.check_if_similar_patch_pushed', mock_check_if_similar_patch_pushed) midstream_git = git_at(midstream_repo) if call_with_env: monkeypatch.setenv('REPO_URL', str(midstream_repo)) monkeypatch.setenv('REPO_REF', 'refs/heads/master') monkeypatch.setenv('REPO_PUSH_BRANCH', 'other_branch') monkeypatch.setenv('PUSHER_PUSH_MAP', str(gerrit_push_map)) run_click_command(updater_main_cli, '-d', '-v') else: run_click_command(updater_main_cli, '-d', '-v', str(midstream_repo), 'refs/heads/master', 'other_branch', str(gerrit_push_map)) assert mock_check_if_similar_patch_pushed.called, \ 'expected check if similar patch pushed to be called' other_branch_sha = git_rev_parse('refs/for/other_branch', midstream_git) head_sha = git_rev_parse('HEAD', midstream_git) assert head_sha == other_branch_sha, \ 'expected push to occur to other_branch and sha to be the same as HEAD'
def test_git_rev_parse(repo_with_patches, git_repo_log, monkeypatch, ref, exp_idx): monkeypatch.chdir(repo_with_patches) if isinstance(exp_idx, type) and issubclass(exp_idx, Exception): with pytest.raises(exp_idx) as e: git_rev_parse(ref) assert e.value.ref == ref else: out = git_rev_parse(ref) assert out == git_repo_log()[exp_idx]
def test_run_upstream_source_updater(midstream_repo, upstream_repo, git_at): upstream_git = git_at(upstream_repo) upstream_head_sha = git_rev_parse('HEAD', upstream_git) midstream_git = git_at(midstream_repo) midstream_head_sha = git_rev_parse('HEAD', midstream_git) midstream_usrc_config = midstream_repo / 'upstream_sources.yaml' run_upstream_source_updater(str(midstream_repo)) with midstream_usrc_config.open() as usrc_config_file: usrc_yaml = yaml.safe_load(usrc_config_file) assert usrc_yaml == { 'git': [{ 'commit': upstream_head_sha, 'branch': 'master', 'url': str(upstream_repo), }] } assert git_rev_parse('HEAD', midstream_git) != midstream_head_sha, \ 'expected a new commit sha on the midstream repository'
def get_patch_owner(push_details, commit='HEAD'): """Get the Gerrit username for the owner of the given commit :param PushDetails push_details: Details about where we're pushing the patch to :param str commit: (Optional) A commit ref for a commit in $PWD, Defaults to HEAD. :rtype: str :returns: The Gerrit username for the owner of the patchset that includes the given commit """ git_hash = git_rev_parse(commit) change_json_lines = gerrit_cli(push_details, 'query', '--format=json', 'commit:' + git_hash).splitlines() if len(change_json_lines) <= 1: return None change = json.loads(change_json_lines[0]) return change['owner']['username']
def test_prep_git_repo( monkeypatch, tmpdir, git_at, repo_with_patches, git_last_sha): # we need this nested tmpdir because `repo_with_patches` exists in the # default tmpdir and the new git repo we initialize will have the same name tmpdir = tmpdir / 'tmpdir' tmpdir.mkdir() monkeypatch.chdir(tmpdir) repo_url = str(repo_with_patches) refspec = 'master' git_func, last_sha = prep_git_repo( tmpdir, repo_url, refspec, checkout=True) # we can't use get-url because on centos7 the git version is too old remote_url = git_func('remote', '-v').split()[1] assert remote_url == repo_url, \ 'expected git func to return the URL for repo_with_patches' assert last_sha == git_rev_parse('HEAD', git_func), ( 'expected to find the fetched sha at the HEAD' ' of the checked out branch' )
def merge_to_scm(push_map, commit='HEAD', check_header='automerge'): """Make a remote SCM merge a given commit :param str push_map: The path to a file containing information about remote SCM servers that is needed to push changes to them. :param str commit: (Optional) A ref to the commit to merge. The default is HEAD :param str check_header: (Optional) The name of a commit header that should be set to 'true' or 'yes' in order for the merge to be attempted. Set to 'automerge' be default, cat be set to None to skip header check. """ if not can_merge_to_scm(push_map, commit, check_header): return commit_hash = git_rev_parse(commit) logger.info("Will merge commit: %s", commit_hash) push_details = read_push_details(push_map) logger.info("Would merge to: '%s'", push_details.push_url) gerrit_cli(push_details, 'review', commit_hash, '--submit', *push_details.merge_flags)
def push_to_scm(dst_branch, push_map, direct=False, if_not_exists=True, unless_hash=None): """Push commits to the specified remote branch :param str dst_branch: The target remote branch to push changes into. What this means in practice depends on the type of remote SCM server being pushed to. :param str push_map: The path to a file containing information about remote SCM servers that is needed to push changes to them. :param bool direct: If set to True, bypass review and directly merge the patch. :param bool if_not_exists: If set to 'True' (the default), check remote for a similar patch before pushing, and don't push if it exists. :param str unless_hash: Given a Git hash value, or a commit ref, if HEAD is equal to this commit, don't try to push it. """ if unless_hash is not None: if get_patch_sha() == git_rev_parse(unless_hash): logger.info("HEAD commit is '%s', skipping push", unless_hash) return push_details = read_push_details(push_map) logger.info("Would push to: '%s'", push_details.push_url) if push_details.host_key: add_key_to_known_hosts(push_details.host_key) if if_not_exists and check_if_similar_patch_pushed(push_details, dst_branch): logger.info('Found similar patch in SCM server, not pushing') return if direct: dest_to_push_to = 'HEAD:refs/heads/{0}'.format(dst_branch) else: dest_to_push_to = 'HEAD:refs/for/{0}'.format(dst_branch) logger.info("Push to: '%s' at '%s'", push_details.push_url, dest_to_push_to) git('push', push_details.push_url, dest_to_push_to)