From cdb785a92e2356fac15b24ed47c9b72075c4b823 Mon Sep 17 00:00:00 2001 From: Giulia Naponiello Date: Aug 15 2018 08:34:11 +0000 Subject: Validate gating.yaml file for Greenwave gating rpkg will validate the gating.yaml file if there is one in the repo. It will ask to Greenwave for that, when a build command is issued. The command will fail if the gating.yaml file is misconfigured. The user will have the chance to disable the check adding a parameter. Signed-off-by: Giulia Naponiello --- diff --git a/pyrpkg/cli.py b/pyrpkg/cli.py index dcd0d5a..f414961 100644 --- a/pyrpkg/cli.py +++ b/pyrpkg/cli.py @@ -500,6 +500,10 @@ class cliClient(object): self.build_parser_common.add_argument( '--fail-fast', action='store_true', default=False, help='Fail the build immediately if any arch fails') + self.build_parser_common.add_argument( + '--skip-remote-rules-validation', action='store_true', default=False, + help=("Don't check if there's a valid gating.yaml file in the repo, where you can " + "define additional policies for Greenwave gating.")) def register_rpm_common(self): """Create a common parser for rpm commands""" @@ -1415,6 +1419,12 @@ see API KEY section of copr-cli(1) man page. nargs='*', help='Limit a scratch build to an arch. May have multiple arches.') + self.container_build_parser.add_argument( + '--skip-remote-rules-validation', + action='store_true', + default=False, + help="Don't check if there's a valid gating.yaml file in the repo") + self.container_build_parser.set_defaults(command=self.container_build) def register_container_build_setup(self): @@ -1491,6 +1501,50 @@ see API KEY section of copr-cli(1) man page. else: return koji_cli.lib.watch_tasks(self.cmd.kojisession, task_ids) + def extract_greenwave_url(self): + greenwave_url = None + if not self.args.skip_remote_rules_validation: + section_name = "%s.greenwave" % self.name + if self.config.has_option(section_name, 'url'): + greenwave_url = self.config.get(section_name, 'url') + return greenwave_url + + def greenwave_validation_gating(self, greenwave_url, data): + response = requests.post( + "%s/%s" % (greenwave_url, 'api/v1.0/validate-gating-yaml'), + data=data, + timeout=30) + return response + + def check_remote_rules_gating(self): + # checking if there is a file gating.yaml in the repo working tree + # with additional policies for the greenwave feature RemoteRule + greenwave_url = self.extract_greenwave_url() + filename = os.path.join(self.args.path, 'gating.yaml') + if (self.args.skip_remote_rules_validation or + not os.path.exists(filename) or + not greenwave_url or self.args.scratch): + return + + # read content from gating.yaml and validate it from greenwave endpoint + with open(filename, 'rb') as gating_file: + response = self.greenwave_validation_gating(greenwave_url, gating_file.read()) + if response.status_code == 400: + raise rpkgError(('Found a gating.yaml file in your repo with additional ' + 'Greenwave policies, but it is not valid. Please fix the file' + ' or skip this check using the parameter' + ' --skip-remote-rules-validation. Error response from ' + 'Greenwave: %s') % (response.json()['message'])) + elif response.status_code != 200: + raise rpkgError(('Found a gating.yaml file in your repo with additional ' + 'Greenwave policies, but it was not possible to validate it for ' + 'an unknown problem. It is possible to skip this check using the ' + 'parameter --skip-remote-rules-validation. Error response from ' + 'Greenwave: %s') % (response.json()['message'])) + else: + self.log.info(("Found a gating.yaml file in the repo and it is properly " + "configured")) + def build(self, sets=None): """Implement build command""" try: @@ -1542,6 +1596,8 @@ see API KEY section of copr-cli(1) man page. # handle uploading the srpm if we got one url = self._handle_srpm_option() + self.check_remote_rules_gating() + return self.cmd.build( skip_tag=self.args.skip_tag, scratch=self.args.scratch, @@ -1736,6 +1792,8 @@ see API KEY section of copr-cli(1) man page. self.log.debug(err_msg % err_args) build_client = self.config.get(self.name, "build_client") + self.check_remote_rules_gating() + self.cmd.container_build_koji( target_override, opts=opts, diff --git a/tests/test_cli.py b/tests/test_cli.py index 2b43d14..b6099b5 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3000,3 +3000,24 @@ class TestBuildPackage(CliTestCase): ['git://localhost/thirdpkg#2ae3f', 'git://localhost/docpkg#45678'], ]) + + @patch('pyrpkg.cli.cliClient.greenwave_validation_gating') + def test_not_allow_to_build_if_gating_yaml_is_invalid(self, greenwave_response): + greenwave_response.return_value = {'status_code': 500} + self.assert_build('build') + session = self.mock_ClientSession.return_value + session.build.assert_not_called() + + @patch('pyrpkg.cli.cliClient.greenwave_validation_gating') + def test_allowed_to_build_if_skipped_gating_yaml_check(self, greenwave_response): + greenwave_response.return_value = {'status_code': 500} + self.assert_build('build', cli_opts=['--skip-remote-rules-validation']) + session = self.mock_ClientSession.return_value + session.build.assert_called_once() + + @patch('pyrpkg.cli.cliClient.greenwave_validation_gating') + def test_allowed_to_build_if_gating_yaml_is_correct(self, greenwave_response): + greenwave_response.return_value = {'status_code': 200} + self.assert_build('build') + session = self.mock_ClientSession.return_value + session.build.assert_called_once()