Exemplo n.º 1
0
def create_git_am_style_history(sg: Path):
    """
    create merge commit in the provided source-git repo

    :param sg: the repo
    """
    hops = sg.joinpath("hops")
    hops.write_text("Amarillo\n")
    git_add_and_commit(directory=sg, message="switching to amarillo hops")

    hops.write_text("Citra\n")
    meta = PatchMetadata(name="citra.patch",
                         squash_commits=True,
                         present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    malt = sg.joinpath("malt")
    malt.write_text("Munich\n")
    meta = PatchMetadata(name="malt.patch",
                         squash_commits=True,
                         present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    malt.write_text("Pilsen\n")
    git_add_and_commit(directory=sg, message="using Pilsen malt")

    malt.write_text("Vienna\n")
    git_add_and_commit(directory=sg,
                       message="actually Vienna malt could be good")

    malt.write_text("Weyermann\n")
    meta = PatchMetadata(name="0001-m04r-malt.patch",
                         squash_commits=True,
                         present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)
Exemplo n.º 2
0
def test_add_patch_with_patch_id(api_instance_source_git, starting_patch_id):
    """check that patches with patch_id set are added to spec correctly"""
    spec_dir = api_instance_source_git.up.absolute_specfile_dir
    spec: Specfile = api_instance_source_git.up.specfile

    # we want to add this patch to the spec
    good_patch_name1 = "hello.patch"
    # we need to create the patch file so that rebase-helper can find it and process it
    good_patch_path1 = spec_dir.joinpath(good_patch_name1)
    good_patch_path1.write_text("")
    good_patch1 = PatchMetadata(
        name=good_patch_name1,
        path=good_patch_path1,
        present_in_specfile=False,
        patch_id=starting_patch_id,
    )
    spec.add_patch(good_patch1)

    assert spec.get_applied_patches()[0].index == starting_patch_id

    # add another, this time without patch_id
    good_patch_name2 = "hello2.patch"
    good_patch_path2 = spec_dir.joinpath(good_patch_name2)
    good_patch_path2.write_text("")
    good_patch2 = PatchMetadata(
        name=good_patch_name2, path=good_patch_path2, present_in_specfile=False
    )
    spec.add_patch(good_patch2)

    # check that index of the second patch is (starting + 1)
    assert spec.get_applied_patches()[1].index == starting_patch_id + 1

    # and now another with an index lower or equal than the last one and check if
    # an exc is thrown b/c that's not supported
    # to change order of patches (people should reorder the git history instead)
    patch_name = "nope.patch"
    if starting_patch_id <= 1:
        bad_patch_id = starting_patch_id + 1
    else:
        bad_patch_id = starting_patch_id - 1
    bad_patch = PatchMetadata(
        name=patch_name, present_in_specfile=False, patch_id=bad_patch_id
    )
    with pytest.raises(PackitException) as exc:
        spec.add_patch(bad_patch)

    assert (
        f"The 'patch_id' requested ({bad_patch.patch_id}) for patch "
        f"{bad_patch.name} is less"
    ) in str(exc.value)
    assert f"to the last used patch ID ({starting_patch_id + 1})" in str(exc.value)
Exemplo n.º 3
0
    def copy_conditional_patches(self):
        """
        for patches which are applied in conditions
        and the condition is evaluated to false during conversion,
        we cannot create a SRPM because rpmbuild wants the patch files present
        and obviously packit doesn't know how to create those

        this method copies all patch files which are defined and are not in the patch metadata
        """
        patch_files_in_commits: Set[str] = set()

        BUILD_git = git.Repo(self.BUILD_repo_path)
        for commit in BUILD_git.iter_commits():
            p = PatchMetadata.from_commit(commit, None)
            if p.present_in_specfile:  # base commit doesn't have any metadata
                patch_files_in_commits.add(p.name)

        all_defined_patches = set(x.get_patch_name()
                                  for x in self.dist_git_spec.get_patches())

        for patch_name in all_defined_patches - patch_files_in_commits:
            file_src = self.dist_git_path / "SOURCES" / patch_name
            file_dest = self.source_git_path / "SPECS" / patch_name
            logger.debug(f"copying {file_src} to {file_dest}")
            shutil.copy2(file_src, file_dest)
Exemplo n.º 4
0
def test_from_git_trailers():
    commit = flexmock(message="""\
Add a test commit

Patch-name: test.patch
Signed-off-by: Everyday Programmer <*****@*****.**>
""")
    patch_meta = PatchMetadata.from_git_trailers(commit)
    assert patch_meta.name == "test.patch"
Exemplo n.º 5
0
    def _rebase_patches(self):
        """Rebase current branch against the from_branch."""
        to_branch = "dist-git-commits"  # temporary branch to store the dist-git history
        BUILD_dir = self.get_BUILD_dir()
        prep_repo = git.Repo(BUILD_dir)
        from_branch = get_default_branch(prep_repo)
        logger.info(f"Rebase patches from dist-git {from_branch}.")
        self.source_git.git.fetch(BUILD_dir, f"+{from_branch}:{to_branch}")

        # transform into {patch_name: patch_id}
        with self.dist_git_specfile.patches() as patches:
            patch_ids = {p.filename: p.number for p in patches}
            patch_comments = {p.filename: p.comments.raw for p in patches}

        # -2 - drop first commit which represents tarball unpacking
        # -1 - reverse order, HEAD is last in the sequence
        patch_commits = list(prep_repo.iter_commits(from_branch))[-2::-1]

        for commit in patch_commits:
            self.source_git.git.cherry_pick(
                commit.hexsha,
                keep_redundant_commits=True,
                allow_empty=True,
                strategy_option="theirs",
            )

            # Annotate commits in the source-git repo with patch_id. This info is not provided
            # during the rpm patching process so we need to do it here.
            metadata = PatchMetadata.from_git_trailers(commit)
            trailers = [("Patch-id", patch_ids[metadata.name])]
            patch_status = ""
            for line in patch_comments.get(metadata.name, []):
                patch_status += f"    # {line}\n"
            if patch_status:
                trailers.append(("Patch-status", f"|\n{patch_status}"))
            trailers.append(
                (FROM_DIST_GIT_TOKEN, self.dist_git.head.commit.hexsha))

            author = None
            # If the commit subject matches the one used in _packitpatch
            # when applying patches with 'patch', get the original (first)
            # author of the patch file in dist-git.
            if commit.message.startswith(f"Apply patch {metadata.name}"):
                author = get_file_author(self.dist_git, metadata.name)
            logger.debug(f"author={author}")

            with commit_message_file(commit.message,
                                     trailers=trailers) as commit_message:
                self.source_git.git.commit(file=commit_message,
                                           author=author,
                                           amend=True,
                                           allow_empty=True)

        self.source_git.git.branch("-D", to_branch)
Exemplo n.º 6
0
def create_patch_mixed_history(sg: Path):
    """
    create a git history where we mix prefix and no-prefix

    :param sg: the repo
    """
    hops = sg.joinpath("hops")
    hops.write_text("Amarillo\n")
    meta = PatchMetadata(name="amarillo.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    hops.write_text("Citra\n")
    meta = PatchMetadata(name="citra.patch",
                         present_in_specfile=True,
                         no_prefix=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    malt = sg.joinpath("malt")
    malt.write_text("Munich\n")
    meta = PatchMetadata(name="malt.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)
Exemplo n.º 7
0
def test_create_srcgit_requre_populated(api_instance_source_git,
                                        tmp_path: Path):
    """
    use requre to create a source-git out of it in a branch with upstream git history
    - this should only layer downstream changes on top
    """
    # clone dist-git
    pkg = "python-requre"
    dist_git_ref = "6b27ffacda06289ca2d546e15b3c96845243005f"
    dist_git_path = tmp_path.joinpath(pkg)
    source_git_path = tmp_path.joinpath("requre-sg")
    FedPKG().clone(pkg, str(dist_git_path), anonymous=True)
    dg_lp = LocalProject(working_dir=dist_git_path)

    # check out specific ref
    subprocess.check_call(["git", "reset", "--hard", dist_git_ref],
                          cwd=dist_git_path)

    # add a patch in there
    spec = Specfile(dist_git_path / f"{pkg}.spec", sources_dir=dist_git_path)
    patch_name = "hello.patch"
    patch_path = dist_git_path.joinpath(patch_name)
    patch_path.write_text(REQURE_PATCH)
    patch = PatchMetadata(name=patch_name,
                          path=patch_path,
                          present_in_specfile=False)
    spec.add_patch(patch)
    dg_lp.stage()
    dg_lp.commit("add the hello patch")
    subprocess.check_call(["fedpkg", "prep"], cwd=dist_git_path)

    # create src-git
    source_git_path.mkdir()
    subprocess.check_call([
        "git", "clone", "https://github.com/packit/requre",
        str(source_git_path)
    ])
    subprocess.check_call(
        ["git", "checkout", "-B", "source-git-0.4.0", "0.4.0"],
        cwd=source_git_path)
    sgg = SourceGitGenerator(
        LocalProject(working_dir=source_git_path),
        api_instance_source_git.config,
        dist_git_path=dist_git_path,
    )
    sgg.create_from_upstream()

    # verify it
    subprocess.check_call(["packit", "srpm"], cwd=source_git_path)
    srpm_path = list(
        source_git_path.glob("python-requre-0.4.0-2.*.src.rpm"))[0]
    assert srpm_path.is_file()
Exemplo n.º 8
0
def create_history_with_empty_commit(sg: Path):
    """
    create a git history with an empty commit

    :param sg: the repo
    """
    hops = sg.joinpath("hops")
    hops.write_text("Amarillo\n")
    meta = PatchMetadata(name="amarillo.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    hops.write_text("Citra\n")
    meta = PatchMetadata(name="citra.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    # https://en.wikipedia.org/wiki/Saaz_hops
    meta = PatchMetadata(name="saaz.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    malt = sg.joinpath("malt")
    malt.write_text("Munich\n")
    meta = PatchMetadata(name="malt.patch", present_in_specfile=True)
    git_add_and_commit(directory=sg, message=meta.commit_message)
Exemplo n.º 9
0
def create_history_with_patch_ids(sg: Path):
    """
    create a git history where patch_ids are set

    :param sg: the repo
    """
    hops = sg.joinpath("hops")
    hops.write_text("Amarillo\n")
    meta = PatchMetadata(name="amarillo.patch",
                         present_in_specfile=False,
                         patch_id=3)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    hops.write_text("Citra\n")
    meta = PatchMetadata(name="citra.patch", present_in_specfile=False)
    git_add_and_commit(directory=sg, message=meta.commit_message)

    malt = sg.joinpath("malt")
    malt.write_text("Munich\n")
    meta = PatchMetadata(name="malt.patch",
                         present_in_specfile=False,
                         patch_id=100)
    git_add_and_commit(directory=sg, message=meta.commit_message)
Exemplo n.º 10
0
    def _rebase_patches(self, patch_comments: Dict[str, List[str]]):
        """Rebase current branch against the from_branch

        Args:
            patch_comments: dict to map patch names to comment lines serving
                as a description of those patches.
        """
        to_branch = "dist-git-commits"  # temporary branch to store the dist-git history
        BUILD_dir = self.get_BUILD_dir()
        prep_repo = git.Repo(BUILD_dir)
        from_branch = get_default_branch(prep_repo)
        logger.info(f"Rebase patches from dist-git {from_branch}.")
        self.source_git.git.fetch(BUILD_dir, f"+{from_branch}:{to_branch}")

        # transform into {patch_name: patch_id}
        patch_ids = {
            p.get_patch_name(): p.index
            for p in self.dist_git_specfile.patches.get("applied", [])
        }

        # -2 - drop first commit which represents tarball unpacking
        # -1 - reverse order, HEAD is last in the sequence
        patch_commits = list(prep_repo.iter_commits(from_branch))[-2::-1]

        for commit in patch_commits:
            self.source_git.git.cherry_pick(
                commit.hexsha,
                keep_redundant_commits=True,
                allow_empty=True,
                strategy_option="theirs",
            )

            # Annotate commits in the source-git repo with patch_id. This info is not provided
            # during the rpm patching process so we need to do it here.
            metadata = PatchMetadata.from_git_trailers(commit)
            # commit.message already ends with \n
            message = commit.message
            message += f"Patch-id: {patch_ids[metadata.name]}\n"
            if patch_comments.get(metadata.name):
                message += "Patch-status: |\n"
            for line in patch_comments.get(metadata.name, []):
                message += f"    # {line}\n"
            self.source_git.git.commit(message=message,
                                       amend=True,
                                       allow_empty=True)

        self.source_git.git.branch("-D", to_branch)
Exemplo n.º 11
0
def test_add_patch_first_id_1(api_instance_source_git):
    """check that add_patch sets the first patch id to 1"""
    spec_dir = api_instance_source_git.up.absolute_specfile_dir
    spec: Specfile = api_instance_source_git.up.specfile

    # we want to add this patch to the spec
    good_patch_name1 = "hello.patch"
    # we need to create the patch file so that rebase-helper can find it and process it
    good_patch_path1 = spec_dir.joinpath(good_patch_name1)
    good_patch_path1.write_text("")
    good_patch1 = PatchMetadata(
        name=good_patch_name1,
        path=good_patch_path1,
        present_in_specfile=False,
    )
    spec.add_patch(good_patch1)

    assert spec.get_applied_patches()[0].index == 1
Exemplo n.º 12
0
def test_undo_identical(git_repo):
    """
    Check that identical patches are correctly detected and changes
    undone in the target git repo.
    """
    input_patch_list = [
        PatchMetadata(name=path.name, path=path)
        for path in Path(git_repo.working_tree_dir).iterdir()
        if path.suffix == ".patch"
    ]
    output_patch_list = [
        x for x in input_patch_list if x.name == "weird-identical.patch"
    ]
    assert (PatchGenerator.undo_identical(input_patch_list,
                                          git_repo) == output_patch_list)
    # 'weird-identical.patch' is identical, except the original patch file
    # is missing a "function" name at one of the hunks, which causes the
    # patch-ids to be different.
    # Is there any safe way to handle this?
    assert [item.a_path for item in git_repo.index.diff(None)
            ] == ["weird-identical.patch"]
Exemplo n.º 13
0
def test_from_patch(patch_file, meta_fields, request):
    patch_path = request.getfixturevalue(patch_file)
    assert PatchMetadata.from_patch(str(patch_path)) == PatchMetadata(
        path=patch_path, **meta_fields)