diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0ef978b087..42444ed4ce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,13 @@ v35.4.0 (unreleased) * Add support when the "components" entry is missing. https://github.com/aboutcode-org/scancode.io/issues/1727 +- Split the functionality of + ``scanpipe.pipes.federatedcode.commit_and_push_changes`` into + ``scanpipe.pipes.federatedcode.commit_changes`` and + ``scanpipe.pipes.federatedcode.push_changes``. Add + ``scanpipe.pipes.federatedcode.write_data_as_yaml``. + + v35.3.0 (2025-08-20) -------------------- diff --git a/scanpipe/pipes/federatedcode.py b/scanpipe/pipes/federatedcode.py index c996582ec2..e7b4990bd4 100644 --- a/scanpipe/pipes/federatedcode.py +++ b/scanpipe/pipes/federatedcode.py @@ -31,6 +31,7 @@ from django.conf import settings import requests +import saneyaml from git import Repo from packageurl import PackageURL @@ -161,6 +162,19 @@ def add_scan_result(project, repo, package_scan_file, logger=None): return relative_scan_file_path +def commit_changes(repo, files_to_commit, commit_message): + """Commit changes to remote repository.""" + repo.index.add(files_to_commit) + repo.index.commit(textwrap.dedent(commit_message)) + + +def push_changes(repo, remote_name="origin", branch_name=""): + """Push changes to remote repository.""" + if not branch_name: + branch_name = repo.active_branch.name + repo.git.push(remote_name, branch_name, "--no-verify") + + def commit_and_push_changes( repo, file_to_commit, purl, remote_name="origin", logger=None ): @@ -177,14 +191,27 @@ def commit_and_push_changes( Signed-off-by: {author_name} <{author_email}> """ - - default_branch = repo.active_branch.name - - repo.index.add([file_to_commit]) - repo.index.commit(textwrap.dedent(commit_message)) - repo.git.push(remote_name, default_branch, "--no-verify") + files_to_commit = [file_to_commit] + commit_changes( + repo=repo, files_to_commit=files_to_commit, commit_message=commit_message + ) + push_changes( + repo=repo, + remote_name=remote_name, + ) def delete_local_clone(repo): """Remove local clone.""" shutil.rmtree(repo.working_dir) + + +def write_data_as_yaml(base_path, file_path, data): + """ + Write the ``data`` as YAML to the ``file_path`` in the ``base_path`` root directory. + Create directories in the path as needed. + """ + write_to = Path(base_path) / Path(file_path) + write_to.parent.mkdir(parents=True, exist_ok=True) + with open(write_to, encoding="utf-8", mode="w") as f: + f.write(saneyaml.dump(data)) diff --git a/scanpipe/tests/pipes/test_federatedcode.py b/scanpipe/tests/pipes/test_federatedcode.py index 0e1fd0c182..2067ed9401 100644 --- a/scanpipe/tests/pipes/test_federatedcode.py +++ b/scanpipe/tests/pipes/test_federatedcode.py @@ -28,6 +28,7 @@ from django.test import TestCase import git +import saneyaml from scanpipe import models from scanpipe.pipes import federatedcode @@ -77,3 +78,28 @@ def test_scanpipe_pipes_federatedcode_delete_local_clone(self): federatedcode.delete_local_clone(repo) self.assertEqual(False, Path(local_dir).exists()) + + def test_scanpipe_pipes_federatedcode_write_data_as_yaml(self): + # create local repo + local_dir = tempfile.mkdtemp() + repo = git.Repo.init(local_dir) + + # write data + data = ["123", "abc", 3] + federatedcode.write_data_as_yaml( + base_path=repo.working_dir, + file_path="test.yml", + data=data, + ) + + # Check if file was written + test_file_path = Path(repo.working_dir) / "test.yml" + self.assertEqual(True, test_file_path.exists()) + with open(test_file_path) as f: + contents = f.read() + yml = saneyaml.load(contents) + expected_results = ["123", "abc", "3"] + self.assertEqual(expected_results, yml) + + # clean up + shutil.rmtree(repo.working_dir)