diff --git a/0014-import_srpm-allow-pre-generated-srpms.patch b/0014-import_srpm-allow-pre-generated-srpms.patch new file mode 100644 index 0000000..f596265 --- /dev/null +++ b/0014-import_srpm-allow-pre-generated-srpms.patch @@ -0,0 +1,105 @@ +From d87cb37fa2fea2ed535b9085a1f4c607083e1c2e Mon Sep 17 00:00:00 2001 +From: Ondrej Nosek +Date: Tue, 4 Apr 2023 01:40:23 +0200 +Subject: [PATCH 1/6] import_srpm: allow pre-generated srpms + +When active, do not care specfile in the srpm is processed by +rpmautospec. Can be activated only directly via pyrpkg 'Commands' +object. + +Relates: https://github.com/fedora-copr/copr/issues/2317 +Fixes: #655 +RHELCMP-11085 + +Signed-off-by: Ondrej Nosek +--- + pyrpkg/__init__.py | 6 +++++- + tests/test_cli.py | 41 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index 9996402..ecb99c9 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -110,7 +110,7 @@ class Commands(object): + build_client, user=None, + dist=None, target=None, quiet=False, + distgit_namespaced=False, realms=None, lookaside_namespaced=False, +- git_excludes=None, results_dir='root'): ++ git_excludes=None, results_dir='root', allow_pre_generated_srpm=False): + """Init the object and some configuration details.""" + + # Path to operate on, most often pwd +@@ -239,6 +239,9 @@ class Commands(object): + # Layout setup + self.layout = layout.build(self.path, + 'resultsdir' if self.results_dir == 'subdir' else None) ++ # A Configuration value used in 'import_srpm' command (comes from the Copr team) ++ # If pre-generated srpms are allowed, don't care specfile is processed by rpmautospec ++ self.allow_pre_generated_srpm = allow_pre_generated_srpm + + # Define properties here + # Properties allow us to "lazy load" various attributes, which also means +@@ -1471,6 +1474,7 @@ class Commands(object): + # the dist-git repo without any specfiles - right after initialization) we are + # not able determine which the main specfile is. + if file.endswith('.spec') and not file.startswith('.') \ ++ and not self.allow_pre_generated_srpm \ + and spec_file_processed_by_rpmautospec(file, target_dir): + raise rpkgError('SRPM was processed by rpmautospec ' + '(specfile "{}" was analyzed)'.format(file)) +diff --git a/tests/test_cli.py b/tests/test_cli.py +index 868ad1f..02620ef 100644 +--- a/tests/test_cli.py ++++ b/tests/test_cli.py +@@ -1784,6 +1784,47 @@ class TestImportSrpm(LookasideCacheMock, CliTestCase): + self.assertFilesExist(['package.rpmlintrc'], search_dir=self.chaos_repo) + self.assertFilesNotExist(['the_file_is_not_in_reserved.yaml'], search_dir=self.chaos_repo) + ++ @patch('pyrpkg.spec_file_processed_by_rpmautospec') ++ def test_import_srpm_not_processed_by_rpmautospec(self, rpmautospec_processed): ++ cli_cmd = ['rpkg', '--path', self.chaos_repo, '--name', 'docpkg', ++ 'import', '--skip-diffs', self.srpm_file] ++ ++ rpmautospec_processed.return_value = False ++ with patch('sys.argv', new=cli_cmd): ++ cli = self.new_cli() ++ with patch('pyrpkg.lookaside.CGILookasideCache.upload', self.lookasidecache_upload): ++ cli.import_srpm() # no exception should be raised ++ rpmautospec_processed.assert_called_once() ++ ++ @patch('pyrpkg.spec_file_processed_by_rpmautospec') ++ def test_import_srpm_processed_by_rpmautospec(self, rpmautospec_processed): ++ cli_cmd = ['rpkg', '--path', self.chaos_repo, '--name', 'docpkg', ++ 'import', '--skip-diffs', self.srpm_file] ++ ++ rpmautospec_processed.return_value = True ++ with patch('sys.argv', new=cli_cmd): ++ cli = self.new_cli() ++ with patch('pyrpkg.lookaside.CGILookasideCache.upload', self.lookasidecache_upload): ++ six.assertRaisesRegex( ++ self, ++ rpkgError, ++ 'SRPM was processed by rpmautospec', ++ cli.import_srpm) ++ rpmautospec_processed.assert_called_once() ++ ++ @patch('pyrpkg.spec_file_processed_by_rpmautospec') ++ def test_import_srpm_processed_by_rpmautospec_allowed(self, rpmautospec_processed): ++ cli_cmd = ['rpkg', '--path', self.chaos_repo, '--name', 'docpkg', ++ 'import', '--skip-diffs', self.srpm_file] ++ ++ rpmautospec_processed.return_value = True ++ with patch('sys.argv', new=cli_cmd): ++ cli = self.new_cli() ++ cli.cmd.allow_pre_generated_srpm = True ++ with patch('pyrpkg.lookaside.CGILookasideCache.upload', self.lookasidecache_upload): ++ cli.import_srpm() # no exception should be raised ++ rpmautospec_processed.assert_not_called() ++ + + class TestMockbuild(CliTestCase): + """Test mockbuild command""" +-- +2.39.2 + diff --git a/0015-Ignore-missing-spec-file-in-pre-push-hook.patch b/0015-Ignore-missing-spec-file-in-pre-push-hook.patch new file mode 100644 index 0000000..b32833c --- /dev/null +++ b/0015-Ignore-missing-spec-file-in-pre-push-hook.patch @@ -0,0 +1,37 @@ +From 3ebfeae20c74de0ca4b26b22135e1996265ea4ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lubom=C3=ADr=20Sedl=C3=A1=C5=99?= +Date: Wed, 5 Apr 2023 11:41:23 +0200 +Subject: [PATCH 2/6] Ignore missing spec file in pre-push hook +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For modules or containers there will be no spec file, and there is +nothing to block the push on. + +Signed-off-by: Lubomír Sedlář +--- + pyrpkg/__init__.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index ecb99c9..d3a7a1c 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -4471,7 +4471,12 @@ class Commands(object): + # Assume, that specfile names are same in the active branch + # and in the pushed branch (git checkout f37 && git push origin rawhide) + # in this case 'f37' is active branch and 'rawhide' is pushed branch. +- specfile_path_absolute = os.path.join(self.layout.specdir, self.spec) ++ try: ++ specfile_path_absolute = os.path.join(self.layout.specdir, self.spec) ++ except rpkgError: ++ # No specfile found, nothing to check ++ return ++ + # convert to relative path + specfile_path = os.path.relpath(specfile_path_absolute, start=self.path) + cmd = ['spectool', '-l', os.path.join(clone_dir, specfile_path)] +-- +2.39.2 + diff --git a/0016-Check-remote-file-with-correct-hash.patch b/0016-Check-remote-file-with-correct-hash.patch new file mode 100644 index 0000000..9bf9eac --- /dev/null +++ b/0016-Check-remote-file-with-correct-hash.patch @@ -0,0 +1,61 @@ +From 4bd4ab1823a7d4bc218b8057b7f00808fabf7648 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lubom=C3=ADr=20Sedl=C3=A1=C5=99?= +Date: Wed, 5 Apr 2023 09:34:33 +0200 +Subject: [PATCH 3/6] Check remote file with correct hash +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The configured hashtype doesn't have to actually be used. There can be +old repos that still use md5. + +JIRA: RHELCMP-11508 +Signed-off-by: Lubomír Sedlář +--- + pyrpkg/__init__.py | 3 ++- + pyrpkg/lookaside.py | 5 +++-- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index d3a7a1c..0b9a869 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -4548,7 +4548,8 @@ class Commands(object): + file_exists_in_lookaside = self.lookasidecache.remote_file_exists_head( + self.ns_repo_name if self.lookaside_namespaced else self.repo_name, + filename, +- hash) ++ hash, ++ hashtype=entry.hashtype) + if not file_exists_in_lookaside: + self.log.error('Source file (or tarball) \'{}\' wasn\'t uploaded to the lookaside ' + 'cache. Push operation was cancelled.'.format(filename)) +diff --git a/pyrpkg/lookaside.py b/pyrpkg/lookaside.py +index ecbf12b..3efcd88 100644 +--- a/pyrpkg/lookaside.py ++++ b/pyrpkg/lookaside.py +@@ -200,7 +200,7 @@ class CGILookasideCache(object): + if not self.file_is_valid(outfile, hash, hashtype=hashtype): + raise DownloadError('%s failed checksum' % filename) + +- def remote_file_exists_head(self, name, filename, hash): ++ def remote_file_exists_head(self, name, filename, hash, hashtype): + """Verify whether a file exists on the lookaside cache. + Uses a HTTP HEAD request and doesn't require authentication. + +@@ -209,10 +209,11 @@ class CGILookasideCache(object): + the server side expects). + :param str filename: The name of the file to check for. + :param str hash: The known good hash of the file. ++ :param str hashtype: The type of hash + """ + + urled_file = urllib.parse.quote(filename) +- url = self.get_download_url(name, urled_file, hash, self.hashtype) ++ url = self.get_download_url(name, urled_file, hash, hashtype or self.hashtype) + + c = pycurl.Curl() + c.setopt(pycurl.URL, url) +-- +2.39.2 + diff --git a/0017-Allow-empty-commits-when-uses_rpmautospec.patch b/0017-Allow-empty-commits-when-uses_rpmautospec.patch new file mode 100644 index 0000000..448cbc9 --- /dev/null +++ b/0017-Allow-empty-commits-when-uses_rpmautospec.patch @@ -0,0 +1,35 @@ +From d2c63c32306732695b7fe5f9dda3deecb7899f4f Mon Sep 17 00:00:00 2001 +From: Jiri Kyjovsky +Date: Sat, 15 Apr 2023 13:46:21 +0200 +Subject: [PATCH 4/6] Allow empty commits when `uses_rpmautospec` + +To avoid situations where the command `commit` by default does +commit when no change in repo is present. + +Fixes: #677 +JIRA: RHELCMP-11489 +Merges: https://pagure.io/rpkg/pull-request/688 + +Signed-off-by: Jiri Kyjovsky +--- + pyrpkg/__init__.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index 0b9a869..187796e 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -1867,7 +1867,9 @@ class Commands(object): + + # construct the git command + # We do this via subprocess because the git module is terrible. +- cmd = ['git', 'commit', '--allow-empty'] ++ cmd = ['git', 'commit'] ++ if not self.is_retired() and self.uses_rpmautospec: ++ cmd.append('--allow-empty') + if signoff: + cmd.append('-s') + if self.quiet: +-- +2.39.2 + diff --git a/0018-Config-file-option-to-skip-the-hook-script-creation.patch b/0018-Config-file-option-to-skip-the-hook-script-creation.patch new file mode 100644 index 0000000..fa9aa01 --- /dev/null +++ b/0018-Config-file-option-to-skip-the-hook-script-creation.patch @@ -0,0 +1,126 @@ +From b48eb502d330ec7a543805d7f185ea270df75b90 Mon Sep 17 00:00:00 2001 +From: Ondrej Nosek +Date: Wed, 12 Apr 2023 00:42:04 +0200 +Subject: [PATCH 5/6] Config file option to skip the hook script creation + +A new option named "skip_hooks" can be added to the config file +(into the main section). It accepts boolean values and when +the option is present and set, it prevents creating the pre-push +hook script during cloning a dist-git repository. + +Fixes: https://pagure.io/fedpkg/issue/515 +JIRA: RHELCMP-11491 + +Signed-off-by: Ondrej Nosek +--- + pyrpkg/__init__.py | 14 ++++++++++---- + pyrpkg/cli.py | 13 +++++++++++-- + 2 files changed, 21 insertions(+), 6 deletions(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index 187796e..7fddff7 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -1571,7 +1571,7 @@ class Commands(object): + + def clone(self, repo, path=None, branch=None, bare_dir=None, + anon=False, target=None, depth=None, extra_args=None, +- config_path=None): ++ config_path=None, skip_hooks=None): + """Clone a repo, optionally check out a specific branch. + + :param str repo: the name of the repository to clone. +@@ -1589,6 +1589,7 @@ class Commands(object): + :param list extra_args: additional arguments that are passed to + the clone command. + :param str config_path: path to the global config file ++ :param bool skip_hooks: skip creation pre-push hook script + """ + + if not path: +@@ -1644,7 +1645,8 @@ class Commands(object): + + if not bare_dir: + self._add_git_excludes(os.path.join(path, git_dir)) +- self._add_git_pre_push_hook(os.path.join(path, git_dir), config_path) ++ if not skip_hooks: ++ self._add_git_pre_push_hook(os.path.join(path, git_dir), config_path) + + return + +@@ -1660,7 +1662,7 @@ class Commands(object): + return repo + + def clone_with_dirs(self, repo, anon=False, target=None, depth=None, +- extra_args=None, config_path=None): ++ extra_args=None, config_path=None, skip_hooks=None): + """Clone a repo old style with subdirs for each branch. + + :param str repo: name of the repository to clone. +@@ -1673,6 +1675,7 @@ class Commands(object): + :param list extra_args: additional arguments that are passed to + the clone command. + :param str config_path: path to the global config file ++ :param bool skip_hooks: skip creation pre-push hook script + """ + + self._push_url = None +@@ -1731,7 +1734,8 @@ class Commands(object): + + # Add excludes + self._add_git_excludes(branch_path) +- self._add_git_pre_push_hook(branch_path, config_path) ++ if not skip_hooks: ++ self._add_git_pre_push_hook(branch_path, config_path) + except (git.GitCommandError, OSError) as e: + raise rpkgError('Could not locally clone %s from %s: %s' + % (branch, repo_path, e)) +@@ -1820,6 +1824,8 @@ class Commands(object): + # This file was generated by {0} when cloning the repository. + # You can edit it to your liking or delete completely. It will not + # be recreated. ++ # Creating this file can be also prevented by adding an option ++ # "skip_hooks = True" into the {0}'s config file; [{0}] section. + + _remote="$1" + _url="$2" +diff --git a/pyrpkg/cli.py b/pyrpkg/cli.py +index 3d8ce33..a1f3f44 100644 +--- a/pyrpkg/cli.py ++++ b/pyrpkg/cli.py +@@ -2177,13 +2177,21 @@ class cliClient(object): + self.log.warning("Repo name should't contain '.git' suffix. " + "Correcting the repo name: '%s'" % repo) + ++ skip_hooks = None ++ if self.config.has_option(self.name, "skip_hooks"): ++ try: ++ skip_hooks = self.config.getboolean(self.name, "skip_hooks") ++ except ValueError: ++ self.log.error("Error: config file option 'skip_hooks'") ++ raise + if self.args.branches: + self.cmd.clone_with_dirs(self.args.repo[0], + anon=self.args.anonymous, + target=self.args.clone_target, + depth=self.args.depth, + extra_args=self.extra_args, +- config_path=self.args.config) ++ config_path=self.args.config, ++ skip_hooks=skip_hooks) + else: + self.cmd.clone(self.args.repo[0], + branch=self.args.branch, +@@ -2191,7 +2199,8 @@ class cliClient(object): + target=self.args.clone_target, + depth=self.args.depth, + extra_args=self.extra_args, +- config_path=self.args.config) ++ config_path=self.args.config, ++ skip_hooks=skip_hooks) + + def commit(self): + if self.args.with_changelog and not self.args.message: +-- +2.39.2 + diff --git a/0019-Pre-push-hook-won-t-check-private-branches.patch b/0019-Pre-push-hook-won-t-check-private-branches.patch new file mode 100644 index 0000000..37a7c52 --- /dev/null +++ b/0019-Pre-push-hook-won-t-check-private-branches.patch @@ -0,0 +1,45 @@ +From 4553da364d7d8a974ab0c08834ee0a54320da2cb Mon Sep 17 00:00:00 2001 +From: Ondrej Nosek +Date: Tue, 18 Apr 2023 16:06:43 +0200 +Subject: [PATCH 6/6] Pre-push hook won't check private branches + +The pre-push hook script was failing the when user tried to push +a private branch. It required using the --release argument with +the pre-push-check command and passing additional arguments into +the hook script. That was found unreliable and private branches +won't be checked. + +Fixes: #683 +JIRA: RHELCMP-11528 + +Signed-off-by: Ondrej Nosek +--- + pyrpkg/__init__.py | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/pyrpkg/__init__.py b/pyrpkg/__init__.py +index 7fddff7..3f934d3 100644 +--- a/pyrpkg/__init__.py ++++ b/pyrpkg/__init__.py +@@ -4489,9 +4489,15 @@ class Commands(object): + specfile_path = os.path.relpath(specfile_path_absolute, start=self.path) + cmd = ['spectool', '-l', os.path.join(clone_dir, specfile_path)] + # extract just '--define' arguments from rpmdefines +- for opt, val in zip(self.rpmdefines[0::2], self.rpmdefines[1::2]): +- if opt == '--define': +- cmd.extend((opt, val)) ++ try: ++ for opt, val in zip(self.rpmdefines[0::2], self.rpmdefines[1::2]): ++ if opt == '--define': ++ cmd.extend((opt, val)) ++ except rpkgError: ++ # this exception was caused probably by using a private branch ++ self.log.warning('The pre-push script can\'t check private branches. ' ++ 'Push operation continues.') ++ return + ret, stdout, _ = self._run_command(cmd, cwd=clone_dir, + return_text=True, return_stdout=True) + if ret != 0: +-- +2.39.2 + diff --git a/rpkg.spec b/rpkg.spec index 290e345..60d99d1 100644 --- a/rpkg.spec +++ b/rpkg.spec @@ -1,6 +1,6 @@ Name: rpkg Version: 1.66 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Python library for interacting with rpm+git License: GPLv2+ and LGPLv2 @@ -47,6 +47,12 @@ Patch10: 0010-pre-push-check-have-to-use-spectool-with-define.patch Patch11: 0011-A-HEAD-query-into-a-lookaside-cache.patch Patch12: 0012-pre-push-hook-script-contains-a-user-s-config.patch Patch13: 0013-Fix-unittests-for-clone-and-pre-push-hook-script.patch +Patch14: 0014-import_srpm-allow-pre-generated-srpms.patch +Patch15: 0015-Ignore-missing-spec-file-in-pre-push-hook.patch +Patch16: 0016-Check-remote-file-with-correct-hash.patch +Patch17: 0017-Allow-empty-commits-when-uses_rpmautospec.patch +Patch18: 0018-Config-file-option-to-skip-the-hook-script-creation.patch +Patch19: 0019-Pre-push-hook-won-t-check-private-branches.patch %description Python library for interacting with rpm+git @@ -263,6 +269,14 @@ example_cli_dir=$RPM_BUILD_ROOT%{_datadir}/%{name}/examples/cli %changelog +* Tue Apr 18 2023 Ondřej Nosek - 1.66-6 +- Patch: Pre-push hook won't check private branches +- Patch: Config file option to skip the hook script creation +- Patch: Allow empty commits when `uses_rpmautospec` +- Patch: Check remote file with correct hash +- Patch: Ignore missing spec file in pre-push hook +- Patch: import_srpm: allow pre-generated srpms + * Sat Apr 1 2023 Ondřej Nosek - 1.66-5 - Patch: Fix unittests for `clone` and pre-push hook script - Patch: pre-push hook script contains a user's config