def test_basic_local_update_using_distgit(cwd_upstream, api_instance, mock_remote_functionality_upstream): """basic propose-downstream test: mock remote API, use local upstream and dist-git""" u, d, api = api_instance mock_spec_download_remote_s(d) api.sync_release(dist_git_branch="main", version="0.1.0") assert (d / TARBALL_NAME).is_file() spec = Specfile(d / "beer.spec") assert spec.expanded_version == "0.1.0" with spec.sections() as sections: package_section = sections.package assert package_section[2] == "# some change" assert package_section[4] == "Name: beer" assert package_section[5] == "Version: 0.1.0" assert package_section[6] == "Release: 1%{?dist}" assert package_section[7] == "Summary: A tool to make you happy" assert (d / "README.packit").is_file() # assert that we have changelog entries for both versions with spec.sections() as sections: changelog = "\n".join(sections.changelog) assert "0.0.0" in changelog assert "0.1.0" in changelog
def test_local_update_generated_spec(cwd_upstream, api_instance, mock_remote_functionality_upstream): """Check that specfile can be generated on clone.""" u, d, api = api_instance mock_spec_download_remote_s(d) flexmock(api).should_receive("init_kerberos_ticket").at_least().once() flexmock(Upstream).should_receive( "get_latest_released_version").and_return("0.1.0") # Simulate generation by moving the spec to a different location # We are checking two things: # * spec-file is not used before the post-upstream-clone # * the version is get from the release state current_spec_location = u / "beer.spec" new_spec_location = u / ".." / "tmp.spec" shutil.move(current_spec_location, new_spec_location) subprocess.check_call(["git", "add", "beer.spec"], cwd=u) subprocess.check_call( ["git", "commit", "-m", "Spec removed from upstream"], cwd=u) api.up.package_config.actions = { ActionName.post_upstream_clone: [f"mv {new_spec_location} {current_spec_location}"] } api.sync_release(dist_git_branch="main") assert (d / TARBALL_NAME).is_file() spec = Specfile(d / "beer.spec") assert spec.expanded_version == "0.1.0" assert (d / "README.packit").is_file() # assert that we have changelog entries for both versions with spec.sections() as sections: changelog = "\n".join(sections.changelog) assert "0.0.0" in changelog assert "0.1.0" in changelog
def test_write_spec_content(specfile): data = "new line 1\n" spec = Specfile(specfile, autosave=True) with spec.sections() as sections: sections.description = [data] assert "new line 1" in specfile.read_text()
def test_basic_local_update_copy_upstream_release_description( cwd_upstream, api_instance, mock_remote_functionality_upstream): """basic propose-downstream test: mock remote API, use local upstream and dist-git, set copy_upstream_release_description in package config to True""" u, d, api = api_instance mock_spec_download_remote_s(d) flexmock(api).should_receive("init_kerberos_ticket").at_least().once() release = flexmock(body="Some description of the upstream release") api.up.local_project.git_project = flexmock( get_release=lambda name, tag_name: release) api.package_config.copy_upstream_release_description = True api.sync_release(dist_git_branch="main", version="0.1.0") assert (d / TARBALL_NAME).is_file() spec = Specfile(d / "beer.spec") assert spec.expanded_version == "0.1.0" assert (d / "README.packit").is_file() # assert that we have changelog entries for both versions with spec.sections() as sections: changelog = "\n".join(sections.changelog) assert ("""- 0.1.0-1 Some description of the upstream release """ in changelog) assert "0.0.0" in changelog assert "0.1.0" in changelog
def test_basic_local_update_empty_patch( distgit_and_remote, mock_remote_functionality_sourcegit, api_instance_source_git, ref, ): """propose-downstream for sourcegit test: mock remote API, use local upstream and dist-git Check that by default commit origin is not marked in dist-git. """ distgit, _ = distgit_and_remote mock_spec_download_remote_s(distgit) api_instance_source_git.sync_release( dist_git_branch="main", version="0.1.0", upstream_ref=ref, ) assert (distgit / TARBALL_NAME).is_file() spec = Specfile(distgit / "beer.spec") assert spec.expanded_version == "0.1.0" with spec.patches() as patches: assert not patches assert "From-source-git-commit" not in git.Repo( distgit).head.commit.message
def test_patch_id_digits(specfile, lines, digits): """Check detecting the number of digits used for patch IDs (indices)""" content = specfile.read_text() content = content.replace("### patches ###\n", lines) specfile.write_text(content) spec = Specfile(specfile, sourcedir=specfile.parent, autosave=True) with spec.patches() as patches: assert patches[0].number_digits == digits
def test_read_patch_comments(specfile, lines, files, expectation): """Check reading comment lines that belong to patches""" content = specfile.read_text() content = content.replace("### patches ###\n", lines) specfile.write_text(content) for patch_file in files: Path(specfile.parent, patch_file).touch() spec = Specfile(specfile, sourcedir=specfile.parent, autosave=True) with spec.patches() as patches: comments = {p.filename: [c.text for c in p.comments] for p in patches} assert comments == expectation
def create_from_upstream(self): """Create a source-git repo, by transforming downstream patches in Git commits applied on top of the selected upstream ref. """ upstream_ref_sha = self.source_git.git.rev_list( "-1", self.upstream_ref) if upstream_ref_sha != self.source_git.head.commit.hexsha: raise PackitException( f"{self.upstream_ref!r} is not pointing to the current HEAD " f"in {self.source_git.working_dir!r}.") with self.dist_git_specfile.prep() as prep: if "%autosetup" not in prep: if not self.ignore_missing_autosetup: raise PackitException( "Initializing source-git repos for packages " "not using %autosetup is not allowed by default. " "You can use --ignore-missing-autosetup option to enforce " "running the command without %autosetup.") logger.warning( "Source-git repos for packages not using %autosetup may be not initialized" "properly or may not work with other packit commands.") self._populate_distro_dir() self._reset_gitignore() self._configure_syncing() spec = Specfile( f"{self.distro_dir}/{self.pkg_name}.spec", sourcedir=self.dist_git.working_dir, autosave=True, ) with spec.patches() as patches: patches.clear() self.source_git.git.stage(DISTRO_DIR, force=True) message = f"""Initialize as a source-git repository {FROM_DIST_GIT_TOKEN}: {self.dist_git.head.commit.hexsha} """ self.source_git.git.commit(message=message) pkg_tool = PkgTool( fas_username=self.config.fas_user, directory=self.dist_git.working_dir, tool=self.pkg_tool or self.config.pkg_tool, ) pkg_tool.sources() self._run_prep() self._rebase_patches()
def set_specfile_content( self, specfile: Specfile, version: Optional[str] = None, comment: Optional[str] = None, ): """ Update this specfile using provided specfile Args: specfile: specfile to get changes from (we update self.specfile) version: version to set in self.specfile comment: new comment for the version in %changelog """ with self.specfile.sections() as sections, specfile.sections( ) as other_sections: try: previous_changelog = sections.changelog[:] except AttributeError: previous_changelog = [] sections[:] = other_sections[:] try: sections.changelog = previous_changelog except AttributeError: sections.append(Section("changelog", previous_changelog)) if version is not None: self.specfile.version = version if comment is not None: self.specfile.add_changelog_entry(comment)
def dist_git_specfile(self) -> Specfile: if not self._dist_git_specfile: path = str(Path(self.dist_git.working_dir, f"{self.pkg_name}.spec")) self._dist_git_specfile = Specfile( path, sourcedir=self.dist_git.working_dir, autosave=True) return self._dist_git_specfile
def test_basic_local_update_without_patching( sourcegit_and_remote, distgit_and_remote, mock_remote_functionality_sourcegit, api_instance_source_git, ): """propose-downstream for sourcegit test: mock remote API, use local upstream and dist-git Check that the upstream commit hash is saved when 'mock_commit_origin' is set. """ sourcegit, _ = sourcegit_and_remote distgit, _ = distgit_and_remote mock_spec_download_remote_s(distgit) api_instance_source_git.sync_release( dist_git_branch="main", version="0.1.0", upstream_ref="0.1.0", mark_commit_origin=True, ) assert (distgit / TARBALL_NAME).is_file() spec = Specfile(distgit / "beer.spec") assert spec.expanded_version == "0.1.0" assert (f"From-source-git-commit: {git.Repo(sourcegit).head.commit.hexsha}" in git.Repo(distgit).head.commit.message)
def specfile(self) -> Specfile: if self._specfile is None: self._specfile = Specfile( self.absolute_specfile_path, sourcedir=self.absolute_source_dir, autosave=True, ) return self._specfile
def test_basic_local_update(cwd_upstream, api_instance, mock_remote_functionality_upstream): """basic propose-downstream test: mock remote API, use local upstream and dist-git""" u, d, api = api_instance mock_spec_download_remote_s(d) flexmock(api).should_receive("init_kerberos_ticket").at_least().once() api.sync_release(dist_git_branch="main", version="0.1.0") assert (d / TARBALL_NAME).is_file() spec = Specfile(d / "beer.spec") assert spec.expanded_version == "0.1.0" assert (d / "README.packit").is_file() # assert that we have changelog entries for both versions with spec.sections() as sections: changelog = "\n".join(sections.changelog) assert "0.0.0" in changelog assert "0.1.0" in changelog
def test_remove_patches_no_blanklines(specfile): no_blanks = specfile.read_text().replace("\n\n", "\n") no_patches = no_blanks.replace("\n### patches ###\n", "\n") patches = no_blanks.replace( "### patches ###\n", """\ # Some comment line to be removed Patch1: yellow.patch Patch2: blue.patch # One # Or more lines Patch : dark.patch """, ) specfile.write_text(patches) spec = Specfile(specfile, sourcedir=specfile.parent, autosave=True) with spec.patches() as patches: patches.clear() assert specfile.read_text() == no_patches
def test_basic_local_update_from_downstream( cwd_upstream, api_instance, mock_remote_functionality_upstream): flexmock(LocalProject, _parse_namespace_from_git_url=lambda: None) u, d, api = api_instance api.sync_from_downstream("main", "main", True) new_upstream = api.up.local_project.working_dir assert (new_upstream / "beer.spec").is_file() spec = Specfile(new_upstream / "beer.spec") assert spec.expanded_version == "0.0.0"
def test_download_remote_sources_via_spec(self): """ Use case: package_config.sources and Source0 are out of sync, make sure packit downloads correct archive specifiec in the spec file """ # we should use an actual git.centos.org url but we'd store the tarball in our history # which we don't want I'd say # "https://git.centos.org/sources/rsync/c8s/82e7829c0b3cefbd33c233005341e2073c425629" git_centos_org_url = "https://example.org/" package_config = PackageConfig( specfile_path="rsync.spec", sources=[ SourcesItem( path="rsync-3.1.2.tar.gz", url=git_centos_org_url, ), ], jobs=[], ) # same drill here, let's not store tarballs in our git-history # source = "https://download.samba.org/pub/rsync/src/rsync-3.1.3.tar.gz" source = "https://httpbin.org/anything/rsync-3.1.3.tar.gz" base_git = PackitRepositoryBase(config=flexmock(), package_config=package_config) specfile_content = ("Name: rsync\n" "Version: 3.1.3\n" "Release: 1\n" f"Source0: {source}\n" "License: GPLv3+\n" "Summary: rsync\n" "%description\nrsync\n") tmp = Path(self.static_tmp) spec_path = tmp / "rsync.spec" spec_path.write_text(specfile_content) specfile = Specfile(spec_path, sourcedir=tmp, autosave=True) flexmock(base_git).should_receive("specfile").and_return(specfile) def mocked_is_file(): import inspect # return False only if Path.is_file() is called directly from within # the download_remote_sources() method # this is necessary because specfile relies on Path.is_file() as well return inspect.stack()[3].function != "download_remote_sources" flexmock(Path).should_receive("is_file").replace_with(mocked_is_file) base_git.download_remote_sources() expected_path = tmp / "rsync-3.1.3.tar.gz" assert Path(expected_path).exists()
def test_basic_local_update_direct_push(cwd_upstream, api_instance, distgit_and_remote, mock_remote_functionality_upstream): """basic propose-downstream test: mock remote API, use local upstream and dist-git""" u, d, api = api_instance _, distgit_remote = distgit_and_remote mock_spec_download_remote_s(d) api.sync_release(dist_git_branch="main", version="0.1.0", create_pr=False) remote_dir_clone = Path(f"{distgit_remote}-clone") subprocess.check_call( ["git", "clone", distgit_remote, str(remote_dir_clone)], cwd=str(remote_dir_clone.parent), ) spec = Specfile(remote_dir_clone / "beer.spec") assert spec.expanded_version == "0.1.0" assert (remote_dir_clone / "README.packit").is_file()
def test_basic_local_update_direct_push_no_dg_spec( cwd_upstream, api_instance, distgit_and_remote, mock_remote_functionality_upstream): u, d, api = api_instance d.joinpath("beer.spec").unlink() subprocess.check_call( ["git", "commit", "-m", "remove spec", "-a"], cwd=str(d), ) _, distgit_remote = distgit_and_remote mock_spec_download_remote_s(d) api.sync_release(dist_git_branch="main", version="0.1.0", create_pr=False) remote_dir_clone = Path(f"{distgit_remote}-clone") subprocess.check_call( ["git", "clone", distgit_remote, str(remote_dir_clone)], cwd=str(remote_dir_clone.parent), ) spec = Specfile(remote_dir_clone / "beer.spec") assert spec.expanded_version == "0.1.0" assert (remote_dir_clone / "README.packit").is_file()
def test_set_spec_has_autochangelog(spec_content, has_autochangelog, tmp_path): spec_path = tmp_path / "life.spec" spec_path.write_text(spec_content) specfile = Specfile(spec_path, sourcedir=tmp_path, autosave=True) assert specfile.has_autochangelog == has_autochangelog