def push_submodule(self, project, submodule_url, destination_dir, branch="master", fast_forward=True, message=None): """ Push a submodule to the given project. It is assumed that the project has been created. """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") to_write = repo_src.join(destination_dir) if to_write.exists(): raise RuntimeError("path %s already exists" % destination_dir) if not message: message = "Add submodule %s" % destination_dir git.call("submodule", "add", submodule_url, destination_dir) git.add(destination_dir) git.commit("--message", message) if fast_forward: git.push("origin", "%s:%s" % (branch, branch)) else: git.push("origin", "--force", "%s:%s" % (branch, branch))
def diff_worktree(git_worktree, git_projects, branch, cmd=None): """ Run `git <cmd> local_branch..remote_branch` for every project """ if not cmd: cmd = ["log"] remote_projects = git_worktree.get_projects_on_branch(branch) for git_project in git_projects: remote_project = remote_projects.get(git_project.src) if not remote_project: continue git = qisrc.git.Git(git_project.path) local_branch = git.get_current_branch() remote_branch = remote_project.default_branch.name remote_ref = "%s/%s" % (remote_project.default_remote.name, remote_branch) rc, out = git.call("merge-base", local_branch, remote_ref, raises=False) if rc != 0: continue merge_base = out.strip() full_cmd = cmd + ["%s..%s" % (merge_base, local_branch)] color = ui.config_color(sys.stdout) if color: full_cmd.append("--color=always") rc, out = git.call(*full_cmd, raises=False) if rc != 0: continue if not out: continue ui.info(ui.bold, git_project.src) ui.info(ui.bold, "-" * len(git_project.src)) ui.info(out) ui.info()
def test_switching_from_fixed_ref_to_branch_local_changes( qisrc_action, git_server, record_messages): """ Test Swithcing From Fixed Ref To Branch Local Changes """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_tag("foo.git", "v0.2") git_server.push_file("foo.git", "c.txt", "c") git_server.set_fixed_ref("foo.git", "v0.1") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = TestGit(foo_proj.path) git.write_file("a.txt", "unstaged changes") git_server.set_branch("foo.git", "master") record_messages.reset() rc = qisrc_action("sync", retcode=True) # ERROR message must be displayed to warn user assert rc != 0 assert record_messages.find("unstaged changes") _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") # git repo unchanged assert sha1 == expected git.call("reset", "--hard") qisrc_action("sync", retcode=True) # if modification is revert sync must be successful assert git.get_current_branch() == "master"
def test_switching_from_fixed_ref_to_branch_local_changes(qisrc_action, git_server, record_messages): """ Test Swithcing From Fixed Ref To Branch Local Changes """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_tag("foo.git", "v0.2") git_server.push_file("foo.git", "c.txt", "c") git_server.set_fixed_ref("foo.git", "v0.1") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = TestGit(foo_proj.path) git.write_file("a.txt", "unstaged changes") git_server.set_branch("foo.git", "master") record_messages.reset() rc = qisrc_action("sync", retcode=True) # ERROR message must be displayed to warn user assert rc != 0 assert record_messages.find("unstaged changes") _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") # git repo unchanged assert sha1 == expected git.call("reset", "--hard") qisrc_action("sync", retcode=True) # if modification is revert sync must be successful assert git.get_current_branch() == "master"
def clever_reset_ref(git_project, ref, raises=True): """ Resets only if needed, fetches only if needed """ try: remote_name = git_project.default_remote.name except AttributeError: error_msg = "Project {} has no default remote, defaulting to origin" ui.error(error_msg.format(git_project.name)) remote_name = "origin" git = qisrc.git.Git(git_project.path) # Deals with "refs/" prefixed ref first if ref.startswith("refs/"): return _reset_hard_to_refs_prefixed_ref(git, remote_name, ref, raises=raises) # Else, ref format is a local name (branch or tag) # Check if this ref exists and if we are already in the expected state rc, ref_sha1 = git.call("rev-parse", ref, "--", raises=False) if rc != 0: # Maybe this is a newly pushed tag, try to fetch: git.fetch(remote_name, "--prune") rc, ref_sha1 = git.call("rev-parse", ref, "--", raises=False) if rc != 0: return False, "Could not parse %s as a valid ref" % ref _, actual_sha1 = git.call("rev-parse", "HEAD", raises=False) if actual_sha1 == ref_sha1: # Nothing to do return None if raises else True, "" # Reset to the ref local name return _reset_hard_to_local_refs_name(git, remote_name, ref, raises=raises)
def stat_tracking_remote(git, branch, tracking): """Check if branch is ahead and / or behind tracking.""" if branch is None or tracking is None: return 0, 0 _, local_ref = git.call("rev-parse", branch, raises=False) _, remote_ref = git.call("rev-parse", tracking, raises=False) return stat_ahead_behind(git, local_ref, remote_ref)
def _test_switching_to_fixed_ref_happy(qisrc_action, git_server, record_messages, tag_ref_to_test, branch_ref_to_test): git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_branch("foo.git", "feature/b") git_server.push_file("foo.git", "c.txt", "c") qisrc_action("init", git_server.manifest_url) # Check for fixed_ref tag git_server.set_fixed_ref("foo.git", tag_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add a.txt") _, status_output = git.status(raises=False) assert "HEAD" in status_output assert "detached" in status_output # If branch ref name is local, makesure it exists on local copy, then go back to master if branch_ref_to_test == "feature/b": git.checkout("feature/b", raises=False) git.checkout("master", raises=False) # Check for fixed_ref branch git_server.set_fixed_ref("foo.git", branch_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/remotes/origin/feature/b") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add b.txt") _, status_output = git.status(raises=False) # FIXME: when using ref long name branch (refs/xxx), if we come from a tag, we stay in a detached head, # and we should be in an attached head state to be consistent with the ref short name branc behaviour # That's not an issue for now as users reference short name in manifest, but it will be cleaner to be consistent... if not branch_ref_to_test.startswith("refs/"): assert "HEAD" not in status_output assert "detached" not in status_output else: # Remove these assert when dealing with behaviour consistency mentionned above assert "HEAD" in status_output assert "detached" in status_output
def clever_reset_ref(git_project, ref, raises=True): """ Resets only if needed, fetches only if needed """ try: remote_name = git_project.default_remote.name except AttributeError: error_msg = "Project {} has no default remote, defaulting to origin" ui.error(error_msg.format(git_project.name)) remote_name = "origin" git = qisrc.git.Git(git_project.path) # Deals with "refs/" prefixed ref first if ref.startswith("refs/"): return _reset_hard_to_refs_prefixed_ref(git, remote_name, ref, raises=raises) # Else, ref format is a local name (branch or tag) # Check if this ref exists and if we are already in the expected state rc, ref_sha1 = git.call("rev-parse", ref, "--", raises=False) if rc != 0: # Maybe this is a newly pushed tag, try to fetch: git.fetch(remote_name) rc, ref_sha1 = git.call("rev-parse", ref, "--", raises=False) if rc != 0: return False, "Could not parse %s as a valid ref" % ref _, actual_sha1 = git.call("rev-parse", "HEAD", raises=False) if actual_sha1 == ref_sha1: # Nothing to do return None if raises else True, "" # Reset to the ref local name return _reset_hard_to_local_refs_name(git, remote_name, ref, raises=raises)
def stat_tracking_remote(git, branch, tracking): """ Check if branch is ahead and / or behind tracking. """ if branch is None or tracking is None: return 0, 0 _, local_ref = git.call("rev-parse", branch, raises=False) _, remote_ref = git.call("rev-parse", tracking, raises=False) return stat_ahead_behind(git, local_ref, remote_ref)
def push_branch(self, project, branch): """ push branch on project """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) # create the branch git.call("branch", branch) git.push("origin", branch)
def delete_file(self, project, filename): """ Delete a file from the repository """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) git.call("rm", filename) git.commit("--message", "remove %s" % filename) git.push("origin", "master:master")
def _test_switching_to_fixed_ref_happy(qisrc_action, git_server, record_messages, tag_ref_to_test, branch_ref_to_test): """ Test Switching To Fixed Ref Happy """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_branch("foo.git", "feature/b") git_server.push_file("foo.git", "c.txt", "c") qisrc_action("init", git_server.manifest_url) # Check for fixed_ref tag git_server.set_fixed_ref("foo.git", tag_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add a.txt") _, status_output = git.status(raises=False) assert "HEAD" in status_output assert "detached" in status_output # If branch ref name is local, makesure it exists on local copy, then go back to master if branch_ref_to_test == "feature/b": git.checkout("feature/b", raises=False) git.checkout("master", raises=False) # Check for fixed_ref branch git_server.set_fixed_ref("foo.git", branch_ref_to_test) qisrc_action("sync") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/remotes/origin/feature/b") assert sha1 == expected # qisrc.reset.clever_reset_ref should tell where is the HEAD after reset record_messages.reset() qisrc_action("sync") assert record_messages.find("HEAD is now at") assert record_messages.find("Add b.txt") _, status_output = git.status(raises=False) # FIXME: when using ref long name branch (refs/xxx), if we come from a tag, we stay in a detached head, # and we should be in an attached head state to be consistent with the ref short name branc behaviour # That's not an issue for now as users reference short name in manifest, but it will be cleaner to be consistent... if not branch_ref_to_test.startswith("refs/"): assert "HEAD" not in status_output assert "detached" not in status_output else: # Remove these assert when dealing with behaviour consistency mentionned above assert "HEAD" in status_output assert "detached" in status_output
def test_fixed_ref_behind(qisrc_action, git_server, record_messages): git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.set_fixed_ref("foo.git", "v0.1") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) git.call("reset", "--hard", "HEAD~1") qisrc_action("status") assert record_messages.find("fixed ref v0.1 -1")
def test_fixed_ref_behind(qisrc_action, git_server, record_messages): """ Test Fixed Ref Behind """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.set_fixed_ref("foo.git", "v0.1") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = qisrc.git.Git(foo_proj.path) git.call("reset", "--hard", "HEAD~1") qisrc_action("status") assert record_messages.find("fixed ref v0.1 -1")
def test_git_get_local_branches(tmpdir): tmpdir = tmpdir.strpath git = qisrc.git.Git(tmpdir) # pylint: disable-msg=E1101 with pytest.raises(Exception): git.get_local_branches() write_readme(tmpdir, "readme\n") git.call("init") git.call("add", ".") git.commit("-m", "initial commit") assert git.get_local_branches() == ["master"] git.checkout("-b", "devel") assert git.get_local_branches() == ["devel", "master"]
def stat_tracking_remote(git, branch, tracking): """Check if branch is ahead and / or behind tracking.""" behind = 0 ahead = 0 (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (tracking, branch), raises=False) if ret == 0: ahead = len(out.split()) (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (branch, tracking), raises=False) if ret == 0: behind = len(out.split()) return (ahead, behind)
def test_new_project_under_review(tmpdir, git_server): foo_repo = git_server.create_repo("foo.git", review=False) assert foo_repo.review is False git_server.use_review("foo.git") foo_repo = git_server.get_repo("foo.git") assert foo_repo.review is True assert foo_repo.review_remote.name == "gerrit" git = qisrc.git.Git(tmpdir.strpath) rc, out = git.call("ls-remote", foo_repo.clone_url, raises=False) assert rc == 0 git = qisrc.git.Git(tmpdir.strpath) rc, out = git.call("ls-remote", foo_repo.review_remote.url, raises=False) assert rc == 0
def clever_reset_ref(git_project, ref, raises=True): """ Resets only if needed, fetches only if needed """ try: remote_name = git_project.default_remote.name except AttributeError: error_msg = "Project {} has no default remote, defaulting to origin" ui.error(error_msg.format(git_project.name)) remote_name = "origin" git = qisrc.git.Git(git_project.path) if ref.startswith("refs/"): if raises: git.fetch(remote_name, ref) git.reset("--hard", "FETCH_HEAD") return else: with git.tansaction() as transaction: git.fetch(remote_name, ref) git.reset("--hard", "FETCH_HEAD") return transaction.ok, transaction.output rc, ref_sha1 = git.call("rev-parse", ref, raises=False) if rc != 0: # Maybe this is a newly pushed tag, try to fetch: git.fetch(remote_name) rc, ref_sha1 = git.call("rev-parse", ref, raises=False) if rc != 0: return False, "Could not parse %s as a valid ref" % ref _, actual_sha1 = git.call("rev-parse", "HEAD", raises=False) if actual_sha1 == ref_sha1: # Nothing to do if raises: return else: return True, "" ret, _ = git.call("show", "--oneline", ref, raises=False) if ret == 0: # SHA-1 exists locally if raises: git.reset("--hard", ref) else: rc, out = git.reset("--hard", ref, raises=False) return (rc == 0), out else: # Full fetch in this case if raises: git.fetch(remote_name) git.reset("--hard", ref) else: with git.transaction() as transaction: git.fetch(remote_name) git.reset("--hard", ref) return transaction.ok, transaction.output
def push_tag(self, project, tag, branch="master", fast_forward=True): """ push tag on project """ src = project.replace(".git", "") repo_src = self.src.join(src) git = qisrc.git.Git(repo_src.strpath) if git.get_current_branch() != branch: git.checkout("--force", "-B", branch) if not fast_forward: git.reset("--hard", "HEAD~1") # tag the branch git.call("tag", tag) if fast_forward: git.push("origin", tag) else: git.push("origin", "--force", tag)
def __str__(self): """ String Representation of the Toochain """ git_path = qisys.sh.get_share_path("qi", "toolchains", self.name + ".git") sha1 = None if os.path.exists(git_path): git = qisrc.git.Git(git_path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) res = "Toolchain %s\n" % self.name if self.feed_url: res += "Using feed from %s" % self.feed_url if self.feed_name: res += " (feeds/%s.xml)" % self.feed_name if self.feed_branch: res += " on %s" % self.feed_branch if sha1: res += " - %s" % sha1[:8] res += "\n" else: res += "No feed\n" if self.packages: res += " Packages:\n" else: res += "No packages\n" sorted_packages = sorted(self.packages) for package in sorted_packages: res += ui.indent(package.name, 2) if package.version: res += " " + package.version res += "\n" if package.path: res += ui.indent("in " + package.path, 3) + "\n" return res
def _sync_git(repo, url, branch, ref): """ Sync Git """ git = qisrc.git.Git(repo) git.set_remote("origin", url) if git.get_current_branch() != branch: git.checkout("-B", branch) with git.transaction() as transaction: git.call("remote", "update", "--prune", "origin") git.fetch("origin") if ref: to_reset = ref git.reset("--hard", to_reset) else: git.reset("--hard", "origin/%s" % branch) if not transaction.ok: raise Exception("Update failed\n" + transaction.output)
def test_create_empty_repo(tmpdir, git_server): """ Test Create Empty Repo """ foo_repo = git_server.create_repo("foo", empty=True) git = qisrc.git.Git(tmpdir.strpath) rc, out = git.call("ls-remote", foo_repo.clone_url, raises=False) assert rc == 0 assert not out
def test_displays_git_info(tmpdir, git_server, feed, qitoolchain_action): boost_package = qitoolchain.qipackage.QiPackage("boost", version="1.44") feed.add_package(boost_package) git_server.create_repo("toolchains.git") git_server.change_branch("toolchains.git", "devel") git_server.push_file("toolchains.git", "feeds/bar.xml", feed.feed_xml.read(), branch="devel") feed_url = git_server.get_repo("toolchains.git").clone_url git = qisrc.git.Git(tmpdir.strpath) _, out = git.call("ls-remote", feed_url, "devel", raises=False) devel_sha1 = out.split()[0][:8] qitoolchain_action("create", "--feed-name", "bar", "--branch", "devel", "foo", feed_url) foo_tc = qitoolchain.get_toolchain("foo") as_str = str(foo_tc) print as_str assert "on devel" in as_str assert "(feeds/bar.xml)" in as_str assert "from %s" % feed_url in as_str assert devel_sha1 in as_str
def test_qisrc_checkout_with_branch_to_ref(qisrc_action, git_server): """ Test QiSrc Checkout With Branch to Ref """ manifest_url = git_server.manifest_url git_server.create_repo("foo.git") git_server.create_repo("bar.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.push_tag("bar.git", "v0.2") git_server.push_file("bar.git", "c.txt", "b") qisrc_action("init", manifest_url) git_server.switch_manifest_branch("devel") git_server.set_fixed_ref("foo.git", "v0.1") git_server.set_fixed_ref("bar.git", "v0.2") git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = TestGit(foo_proj.path) assert git.get_current_branch() == "master" qisrc_action("checkout", "devel") _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected bar_proj = git_worktree.get_git_project("bar") bar_git = qisrc.git.Git(bar_proj.path) _, sha1 = bar_git.call("rev-parse", "HEAD", raises=False) expected = bar_git.get_ref_sha1("refs/tags/v0.2") assert sha1 == expected
def test_create_review_repos(tmpdir, git_server): foo_repo = git_server.create_repo("foo", review=True) assert foo_repo.review_remote.name == "gerrit" assert foo_repo.default_remote.name == "origin" git = qisrc.git.Git(tmpdir.strpath) rc, out = git.call("ls-remote", foo_repo.clone_url, raises=False) assert rc == 0
def snapshot(self): """ Return a :py:class`.Snapshot` of the current worktree state """ snapshot = qisrc.snapshot.Snapshot() snapshot.manifest = self.manifest git = qisrc.git.Git(self.syncer.manifest_repo) rc, out = git.call("rev-parse", "HEAD", raises=False) snapshot.manifest.ref = out for git_project in self.git_projects: src = git_project.src git = qisrc.git.Git(git_project.path) rc, out = git.call("rev-parse", "HEAD", raises=False) if rc != 0: ui.error("git rev-parse HEAD failed for", src) continue snapshot.refs[src] = out.strip() return snapshot
def stat_ahead_behind(git, local_ref, remote_ref): """ Returns a tuple (ahead, behind) describing how far from the remote ref the local ref is. """ behind = 0 ahead = 0 (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (remote_ref, local_ref), raises=False) if ret == 0: ahead = len(out.split()) (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (local_ref, remote_ref), raises=False) if ret == 0: behind = len(out.split()) return ahead, behind
def stat_ahead_behind(git, local_ref, remote_ref): """ Returns a tuple (ahead, behind) describing how far from the remote ref the local ref is """ behind = 0 ahead = 0 (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (remote_ref, local_ref), raises=False) if ret == 0: ahead = len(out.split()) (ret, out) = git.call("rev-list", "--left-right", "%s..%s" % (local_ref, remote_ref), raises=False) if ret == 0: behind = len(out.split()) return (ahead, behind)
def test_with_git(qisrc_action): qisrc_action("create", "foo", "--git") worktree = TestWorkTree() foo_proj = worktree.get_project("foo") git = qisrc.git.Git(foo_proj.path) ret, out = git.call("show", "HEAD", raises=False) assert ret == 0 assert ".gitignore" in out
def snapshot(self): """ Return a :py:class`.Snapshot` of the current worktree state """ snapshot = qisrc.snapshot.Snapshot() snapshot.manifest = self.manifest git = qisrc.git.Git(self._syncer.manifest_repo) rc, out = git.call("rev-parse", "HEAD", raises=False) snapshot.manifest.ref = out for git_project in self.git_projects: src = git_project.src git = qisrc.git.Git(git_project.path) rc, out = git.call("rev-parse", "HEAD", raises=False) if rc != 0: ui.error("git rev-parse HEAD failed for", src) continue snapshot.refs[src] = out.strip() return snapshot
def diff_worktree(git_worktree, git_projects, branch, cmd=None): # pylint: disable=too-many-locals """ Run `git <cmd> local_branch..remote_branch` for every project """ if not cmd: cmd = ["log"] remote_projects = git_worktree.get_projects_on_branch(branch) for git_project in git_projects: remote_project = remote_projects.get(git_project.src) if not remote_project: continue git = qisrc.git.Git(git_project.path) local_branch = git.get_current_branch() if not local_branch: message = (ui.brown, "Not on a branch") else: remote_branch = remote_project.default_branch.name remote_ref = "%s/%s" % (remote_project.default_remote.name, remote_branch) rc, out = git.call("merge-base", local_branch, remote_ref, raises=False) if rc != 0: message = (ui.red, "Calling git merge-base failed") else: merge_base = out.strip() full_cmd = cmd + ["%s..%s" % (merge_base, local_branch)] color = ui.config_color(sys.stdout) if color: full_cmd.append("--color=always") rc, out = git.call(*full_cmd, raises=False) if rc != 0: message = (ui.red, "Calling git log failed") else: if out: message = (out, ) else: continue ui.info(ui.bold, git_project.src) ui.info(ui.bold, "-" * len(git_project.src)) ui.info(*message) ui.info()
def _reset_hard_to_local_refs_name(git, remote_name, ref, raises=True): """ deals with the git reset --hard command for short name ref (NOT on the format 'refs/xxx') """ need_to_fetch, _ = git.call("show", "--oneline", ref, "--", raises=False) if need_to_fetch: git.fetch(remote_name, "--tags") # else: SHA-1 already exists locally, no need to fetch _, tag_list = git.tag("-l", ref, raises=False) is_tag = ref == tag_list # Perform effective switch rc, out = _switch_to_git_ref(git, ref, is_tag) return None if raises else (rc == 0), out
def _reset_hard_to_local_refs_name(git, remote_name, ref, raises=True): """ deals with the git reset --hard command for short name ref (NOT on the format 'refs/xxx') """ need_to_fetch, _ = git.call("show", "--oneline", ref, "--", raises=False) if need_to_fetch: git.fetch(remote_name, "--tags", "--prune") # else: SHA-1 already exists locally, no need to fetch _, tag_list = git.tag("-l", ref, raises=False) is_tag = ref == tag_list # Perform effective switch rc, out = _switch_to_git_ref(git, ref, is_tag) return None if raises else (rc == 0), out
def test_git_version(qibuild_action): proj = qibuild_action.add_test_project("gitversion") git = qisrc.git.Git(proj.path) git.call("init") git.call("add", ".") git.call("commit", "--message", "initial commit") git.call("tag", "v0.1") qibuild_action("configure", "gitversion") qibuild_action("make", "gitversion") testversion = qibuild.find.find_bin([proj.sdk_directory], "testversion") process = subprocess.Popen(testversion, stdout=subprocess.PIPE) out, _ = process.communicate() assert out.strip() == "v0.1"
def main(): parser = argparse.ArgumentParser() parser.add_argument("version") args = parser.parse_args() version = args.version this_dir = os.path.dirname(__file__) qibuild_root = os.path.join(this_dir, "..") git = qisrc.git.Git(qibuild_root) ok, message = git.require_clean_worktree() if not ok: raise Exception(message) for filename in FILES_TO_PATCH: full_path = os.path.join(qibuild_root, filename) fix_version_for_file(full_path, "next", version) git.commit("--all", "-m", "qibuild %s" % version) git.call("tag", "v" + version) for filename in FILES_TO_PATCH: full_path = os.path.join(qibuild_root, filename) fix_version_for_file(filename, version, "next") git.commit("--all", "-m", "start next development") print "All OK feel free to push"
def test_is_ff(tmpdir): a_git = tmpdir.mkdir("a_git_project") a_src = a_git.strpath git = qisrc.git.Git(a_src) git.init() write_readme(a_src, "readme\n") git.add(".") git.commit("-m", "initial commit") git.call("branch", "A") write_readme(a_src, "readme2\n") git.add(".") git.commit("-m", "second commit") git.call("branch", "B") (ret, out) = git.call("show-ref", "--verify", "refs/heads/A", raises=False) A_sha1 = out.split()[0] (ret, out) = git.call("show-ref", "--verify", "refs/heads/B", raises=False) B_sha1 = out.split()[0] class Status: pass status = Status() status.mess = "" assert qisrc.git.is_ff(git, status, A_sha1, B_sha1) == True assert qisrc.git.is_ff(git, status, B_sha1, A_sha1) == False assert qisrc.git.is_ff(git, status, A_sha1, A_sha1) == True
def do(args): """Main entry point.""" git_worktree = qisrc.parsers.get_git_worktree(args) git_projects = qisrc.parsers.get_git_projects(git_worktree, args, default_all=True, use_build_deps=args.use_deps) git_grep_opts = args.git_grep_opts if args.path == 'none': git_grep_opts.append("-h") else: git_grep_opts.append("-H") if args.path == 'absolute' or args.path == 'worktree': git_grep_opts.append("-I") git_grep_opts.append("--null") if ui.config_color(sys.stdout): git_grep_opts.append("--color=always") git_grep_opts.append(args.pattern) if not git_projects: qisrc.worktree.on_no_matching_projects(git_worktree, groups=args.groups) sys.exit(0) max_src = max(len(x.src) for x in git_projects) retcode = 1 for i, project in enumerate(git_projects): ui.info_count(i, len(git_projects), ui.green, "Looking in", ui.blue, project.src.ljust(max_src), end="\r") git = qisrc.git.Git(project.path) (status, out) = git.call("grep", *git_grep_opts, raises=False) if out != "": if args.path == 'absolute' or args.path == 'worktree': lines = out.splitlines() out_lines = list() for line in lines: line_split = line.split('\0') prepend = project.src if args.path == 'worktree' else project.path line_split[0] = os.path.join(prepend, line_split[0]) out_lines.append(":".join(line_split)) out = '\n'.join(out_lines) ui.info("\n", ui.reset, out) if status == 0: retcode = 0 if not out: ui.info(ui.reset) sys.exit(retcode)
def test_gen_scm_info(build_worktree, tmpdir): build_worktree.add_test_project("world") hello_proj = build_worktree.add_test_project("hello") git = qisrc.git.Git(hello_proj.path) git.init() git.add(".") git.commit("--message", "initial commit") rc, sha1 = git.call("rev-parse", "HEAD", raises=False) package_xml = tmpdir.join("package.xml").strpath hello_proj.gen_package_xml(package_xml) tree = qisys.qixml.read(package_xml) scm_elem = tree.find("scm") git_elem = scm_elem.find("git") assert git_elem.get("revision") == sha1
def test_tags(qisrc_action, git_server): """ Test Tags """ git_server.create_repo("foo.git") git_server.push_file("foo.git", "a.txt", "a") git_server.push_tag("foo.git", "v0.1") git_server.push_file("foo.git", "b.txt", "b") git_server.set_fixed_ref("foo.git", "v0.1") qisrc_action("init", git_server.manifest_url) git_worktree = TestGitWorkTree() foo_proj = git_worktree.get_git_project("foo") git = TestGit(foo_proj.path) _, sha1 = git.call("rev-parse", "HEAD", raises=False) expected = git.get_ref_sha1("refs/tags/v0.1") assert sha1 == expected
def open_git_feed(toolchain_name, feed_url, name=None, branch="master", first_pass=True): """ Open a Git Feed """ git_path = qisys.sh.get_share_path("qi", "toolchains", toolchain_name + ".git") git = qisrc.git.Git(git_path) if first_pass: if os.path.exists(git_path): git.call("remote", "set-url", "origin", feed_url) git.call("remote", "update", "--prune", "origin") git.call("fetch", "origin", "--quiet") git.call("reset", "--hard", "--quiet", "origin/%s" % branch) else: git.clone(feed_url, "--quiet", "--branch", branch) feed_path = os.path.join(git_path, "feeds", name + ".xml") else: feed_path = feed_url return feed_path
def clever_reset_ref(git_project, ref): """ Resets only if needed, fetches only if needed """ try: remote_name = git_project.default_remote.name except AttributeError: error_msg = "Project {} has no default remote, defaulting to origin" ui.error(error_msg.format(git_project.name)) remote_name = "origin" git = qisrc.git.Git(git_project.path) if ref.startswith("refs/"): git.fetch(remote_name, ref) git.reset("--hard", "FETCH_HEAD") return _, actual_sha1 = git.call("rev-parse", "HEAD", raises=False) if actual_sha1 == ref: # Nothing to do return ret, _ = git.call("show", "--oneline", ref, raises=False) if ret == 0: # SHA-1 exists locally git.reset("--hard", ref) else: # Full fetch in this case git.fetch(remote_name) git.reset("--hard", ref)
def test_push(tmpdir): foo_url = create_git_repo(tmpdir.strpath, "foo") work = tmpdir.mkdir("work") foo_src = work.mkdir("foo") foo_src = foo_src.strpath git = qisrc.git.Git(foo_src) git.clone(foo_url) # this should work: qisrc.review.push(foo_src, "master") (retcode, out) = git.call("ls-remote", "origin", raises=False) assert retcode == 0 assert "refs/for/master" not in out assert "refs/heads/master" in out gerrit_url = create_git_repo(tmpdir.strpath, "foo-gerrit") git.call("remote", "add", "gerrit", gerrit_url) git.set_config("review.remote", "gerrit") git.checkout("-b", "next") qisrc.review.push(foo_src, "next") (retcode, out) = git.call("ls-remote", "gerrit", raises=False) assert retcode == 0 assert "refs/for/next" in out assert "refs/heads/next" not in out
def _add_scm_info(self, package_xml_root): worktree = self.build_worktree.worktree git_worktreee = qisrc.worktree.GitWorkTree(worktree) git_projects = git_worktreee.git_projects parent_git_project = qisys.parsers.find_parent_project(git_projects, self.path) if not parent_git_project: return git = qisrc.git.Git(parent_git_project.path) rc, out = git.call("rev-parse", "HEAD", raises=False) if rc != 0: return sha1 = out.strip() scm_elem = etree.SubElement(package_xml_root, "scm") git_elem = etree.SubElement(scm_elem, "git") git_elem.set("revision", sha1)