diff --git a/setup.py b/setup.py index a33b195..8c2b571 100644 --- a/setup.py +++ b/setup.py @@ -81,6 +81,7 @@ def read_content(filepath): "console_scripts": [ "pubtools-iib-add-bundles = pubtools.iib.iib_ops:add_bundles_main", "pubtools-iib-remove-operators = pubtools.iib.iib_ops:remove_operators_main", + "pubtools-iib-add-deprecations = pubtools.iib.iib_ops:add_deprecations_main", ] }, include_package_data=True, diff --git a/src/pubtools/iib/iib_ops.py b/src/pubtools/iib/iib_ops.py index 76edf6e..632344e 100644 --- a/src/pubtools/iib/iib_ops.py +++ b/src/pubtools/iib/iib_ops.py @@ -55,13 +55,6 @@ "required": False, "type": str, }, - ("--arch",): { - "group": "IIB service", - "help": "architecture to rebuild", - "required": False, - "type": str, - "action": "append", - }, ("--overwrite-from-index",): { "group": "IIB service", "help": ( @@ -117,6 +110,13 @@ "required": False, "type": bool, } +ADD_CMD_ARGS[("--arch",)] = { + "group": "IIB service", + "help": "architecture to rebuild", + "required": False, + "type": str, + "action": "append", +} RM_CMD_ARGS = CMD_ARGS.copy() RM_CMD_ARGS[("--operator",)] = { @@ -126,6 +126,27 @@ "type": str, "action": "append", } +RM_CMD_ARGS[("--arch",)] = { + "group": "IIB service", + "help": "architecture to rebuild", + "required": False, + "type": str, + "action": "append", +} + +ADD_DEPRECATIONS_CMD_ARGS = CMD_ARGS.copy() +ADD_DEPRECATIONS_CMD_ARGS[("--deprecation-schema",)] = { + "group": "IIB service", + "help": "JSON formatted deprecation schema", + "required": True, + "type": str, +} +ADD_DEPRECATIONS_CMD_ARGS[("--operator-package",)] = { + "group": "IIB service", + "help": "operator name", + "required": True, + "type": str, +} def push_items_from_build( @@ -150,7 +171,7 @@ def push_items_from_build( for operator in build_details.removed_operators: item = { "state": state, - "origin": build_details.from_index or "scratch", + "origin": build_details.from_index, "src": None, "filename": operator, "dest": "redhat-operator-index", @@ -159,6 +180,18 @@ def push_items_from_build( "checksums": None, } ret.append(item) + elif build_details.request_type == "add-deprecations": + item = { + "state": state, + "origin": build_details.from_index, + "src": None, + "filename": build_details.operator_package, + "dest": "redhat-operator-index", + "build": build_details.index_image, + "signing_key": None, + "checksums": None, + } + ret.append(item) return ret @@ -185,7 +218,7 @@ def _iib_op_main( operation: str | None = None, items_final_state: str = "PUSHED", ) -> list[dict[Any, Any]] | Any: - if operation not in ("add_bundles", "remove_operators"): + if operation not in ("add_bundles", "remove_operators", "add_deprecations"): raise ValueError("Must set iib operation") pc = pushcollector.Collector.get() @@ -201,6 +234,14 @@ def _iib_op_main( extra_args["deprecation_list"] = args.deprecation_list.split(",") if args.check_related_images: extra_args["check_related_images"] = args.check_related_images + extra_args["arches"] = args.arch + extra_args["bundles"] = args.bundle + if operation == "remove_operators": + extra_args["arches"] = args.arch + extra_args["operators"] = args.operator + if operation == "add_deprecations": + extra_args["operator_package"] = args.operator_package + extra_args["deprecation_schema"] = args.deprecation_schema if args.binary_image: extra_args["binary_image"] = args.binary_image @@ -214,12 +255,7 @@ def _iib_op_main( if args.build_tag: extra_args["build_tags"] = args.build_tag - build_details = bundle_op( - args.index_image, - args.bundle if operation == "add_bundles" else args.operator, - args.arch, - **extra_args, - ) + build_details = bundle_op(args.index_image, **extra_args) push_items = push_items_from_build(build_details, "PENDING") LOG.debug("Updating push items") @@ -251,6 +287,10 @@ def make_rm_operators_parser() -> ArgumentParser: return setup_arg_parser(RM_CMD_ARGS) +def make_add_deprecations_parser() -> ArgumentParser: + return setup_arg_parser(ADD_DEPRECATIONS_CMD_ARGS) + + def add_bundles_main(sysargs: list[str] | None = None) -> list[dict[Any, Any]]: logging.basicConfig(level=logging.INFO) @@ -279,6 +319,21 @@ def remove_operators_main( return _iib_op_main(args, "remove_operators", "DELETED") +def add_deprecations_main( + sysargs: list[str] | None = None, +) -> list[dict[Any, Any]]: + logging.basicConfig(level=logging.INFO) + + parser = make_add_deprecations_parser() + if sysargs: + args = parser.parse_args(sysargs[1:]) + else: + args = parser.parse_args() + process_parsed_args(args, ADD_DEPRECATIONS_CMD_ARGS) + + return _iib_op_main(args, "add_deprecations") + + def _make_iib_build_details_url(host: str, task_id: str) -> str: return "https://%s/api/v1/builds/%s" % (host, task_id) diff --git a/tests/test_iib_ops.py b/tests/test_iib_ops.py index 2895ffe..dd45818 100644 --- a/tests/test_iib_ops.py +++ b/tests/test_iib_ops.py @@ -53,6 +53,13 @@ operator_1_push_item_delete_notpushed = operator_1_push_item_delete_pending.copy() operator_1_push_item_delete_notpushed["state"] = "NOTPUSHED" +operator_1_push_item_ad_pending = operator_1_push_item_pending.copy() +operator_1_push_item_ad_pending["src"] = None +operator_1_push_item_ad = operator_1_push_item_ad_pending.copy() +operator_1_push_item_ad["state"] = "PUSHED" +operator_1_push_item_ad_notpushed = operator_1_push_item_ad_pending.copy() +operator_1_push_item_ad_notpushed["state"] = "NOTPUSHED" + @contextlib.contextmanager def setup_entry_point_py(entry_tuple, environ_vars): @@ -76,7 +83,12 @@ def fixture_iib_client(): ) iibc_patched.return_value.remove_operators.side_effect = ( lambda *args, **kwargs: IIBBuildDetailsModel.from_dict( - fake_tm.setup_task(*args, **kwargs) + fake_tm.setup_task(*args, **dict(list(kwargs.items())+ [("op_type", "rm")])) + ) + ) + iibc_patched.return_value.add_deprecations.side_effect = ( + lambda *args, **kwargs: IIBBuildDetailsModel.from_dict( + fake_tm.setup_task(*args, **dict(list(kwargs.items())+ [("op_type", "add-deprecations")])) ) ) iibc_patched.return_value.get_build.side_effect = fake_tm.get_task @@ -114,8 +126,6 @@ def fixture_common_iib_op_args(): "index-image", "--binary-image", "binary-image", - "--arch", - "arch", "--iib-krb-principal", "example@REALM", "--iib-insecure", @@ -133,8 +143,8 @@ def add_bundles_mock_calls_tester( ): fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1"], - ["arch"], + bundles=["bundle1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -155,8 +165,8 @@ def add_bundles_mock_calls_tester_check_related_images( ): fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1"], - ["arch"], + bundles=["bundle1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -174,8 +184,8 @@ def add_bundles_mock_calls_tester_empty_deprecation_list( ): fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1"], - ["arch"], + bundles=["bundle1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -192,8 +202,8 @@ def add_bundles_mock_calls_tester_deprecation_bundles( ): fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1"], - ["arch"], + bundles=["bundle1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -205,25 +215,7 @@ def add_bundles_mock_calls_tester_deprecation_bundles( ) -def add_bundles_mock_calls_tester_not_called( - fixture_iib_client, - fixture_iib_krb_auth, -): - fixture_iib_client.return_value.add_bundles.assert_called_once_with( - "index-image", - ["bundle1"], - ["arch"], - binary_image="binary-image", - overwrite_from_index=True, - overwrite_from_index_token="overwrite_from_index_token", - build_tags=["extra-tag-1", "extra-tag-2"], - ) - fixture_iib_client.assert_called_once_with( - "iib-server", auth=fixture_iib_krb_auth.return_value, ssl_verify=False - ) - - -def remove_operators_mock_calls_tester_not_called( +def remove_operators_mock_calls_tester( fixture_iib_client, fixture_iib_krb_auth, ): @@ -232,8 +224,8 @@ def remove_operators_mock_calls_tester_not_called( ) fixture_iib_client.return_value.remove_operators.assert_called_once_with( "index-image", - ["1"], - ["arch"], + operators=["operator-1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -241,17 +233,17 @@ def remove_operators_mock_calls_tester_not_called( ) -def remove_operators_mock_calls_tester( +def add_deprecations_mock_calls_tester( fixture_iib_client, fixture_iib_krb_auth, ): fixture_iib_client.assert_called_once_with( "iib-server", auth=fixture_iib_krb_auth.return_value, ssl_verify=False ) - fixture_iib_client.return_value.remove_operators.assert_called_once_with( + fixture_iib_client.return_value.add_deprecations.assert_called_once_with( "index-image", - ["1"], - ["arch"], + deprecation_schema='{"a": "b"}', + operator_package="operator-1", binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -263,22 +255,22 @@ def remove_operators_mock_calls_tester( "extra_args,push_items,mock_calls_tester", [ ( - ["--deprecation-list", "bundle1,bundle2"], + ["--deprecation-list", "bundle1,bundle2", "--arch", "arch"], [operator_1_push_item_pending, operator_1_push_item_pushed], add_bundles_mock_calls_tester_deprecation_bundles, ), ( - ["--deprecation-list", "bundle1", "--build-timeout", "30"], + ["--deprecation-list", "bundle1", "--build-timeout", "30", "--arch", "arch"], [operator_1_push_item_pending, operator_1_push_item_pushed], add_bundles_mock_calls_tester, ), ( - ["--deprecation-list", ""], + ["--deprecation-list", "", "--arch", "arch"], [operator_1_push_item_pending, operator_1_push_item_pushed], add_bundles_mock_calls_tester_empty_deprecation_list, ), ( - ["--check-related-images"], + ["--check-related-images", "--arch", "arch"], [operator_1_push_item_pending, operator_1_push_item_pushed], add_bundles_mock_calls_tester_check_related_images, ), @@ -369,7 +361,7 @@ def test_add_bundles_py( retval = entry_func( ["cmd"] + fixture_common_iib_op_args - + ["--bundle", "bundle1", "--check-related-images"] + + ["--bundle", "bundle1", "--check-related-images", "--arch", "arch"] ) assert isinstance(retval, IIBBuildDetailsModel) @@ -379,8 +371,8 @@ def test_add_bundles_py( ) fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1"], - ["arch"], + bundles=["bundle1"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -413,7 +405,7 @@ def test_add_bundles_py_multiple_bundles( retval = entry_func( ["cmd"] + fixture_common_iib_op_args - + ["--bundle", "bundle1", "--bundle", "bundle2"] + + ["--bundle", "bundle1", "--bundle", "bundle2", "--arch", "arch"] ) assert isinstance(retval, IIBBuildDetailsModel) @@ -423,8 +415,8 @@ def test_add_bundles_py_multiple_bundles( ) fixture_iib_client.return_value.add_bundles.assert_called_once_with( "index-image", - ["bundle1", "bundle2"], - ["arch"], + bundles=["bundle1", "bundle2"], + arches=["arch"], binary_image="binary-image", overwrite_from_index=True, overwrite_from_index_token="overwrite_from_index_token", @@ -436,7 +428,7 @@ def test_add_bundles_py_multiple_bundles( "extra_args,push_items,mock_calls_tester", [ ( - [], + ["--arch", "arch"], [operator_1_push_item_delete_pending, operator_1_push_item_deleted], remove_operators_mock_calls_tester, ), @@ -461,7 +453,7 @@ def test_remove_operators_cli( with setup_entry_point_cli( ("pubtools_iib", "console_scripts", "pubtools-iib-remove-operators"), "pubtools-iib-remove-operators", - fixture_common_iib_op_args + ["--operator", "1"] + extra_args, + fixture_common_iib_op_args + ["--operator", "operator-1"] + extra_args, { "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", }, @@ -496,7 +488,7 @@ def test_remove_operators_cli_error( with setup_entry_point_cli( ("pubtools_iib", "console_scripts", "pubtools-iib-remove-operators"), "pubtools-iib-remove-operators", - fixture_common_iib_op_args + ["--operator", "1"], + fixture_common_iib_op_args + ["--operator", "operator-1"], { "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", }, @@ -528,7 +520,7 @@ def test_remove_operators_py( "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", }, ) as entry_func: - retval = entry_func(["cmd"] + fixture_common_iib_op_args + ["--operator", "1"]) + retval = entry_func(["cmd"] + fixture_common_iib_op_args + ["--operator", "operator-1", "--arch", "arch"]) assert isinstance(retval, IIBBuildDetailsModel) @@ -538,6 +530,99 @@ def test_remove_operators_py( ) +def test_add_deprecations_cli( + fixture_iib_client, + fixture_iib_krb_auth, + fixture_common_iib_op_args, + fixture_pushcollector, +): + fixture_iib_client.return_value.add_deprecations.side_effect = ( + lambda *args, **kwargs: IIBBuildDetailsModel.from_dict( + fake_tm.setup_task( + *args, **dict(list(kwargs.items()) + [("op_type", "add-deprecations")]) + ) + ) + ) + with setup_entry_point_cli( + ("pubtools_iib", "console_scripts", "pubtools-iib-add-deprecations"), + "pubtools-iib-add-deprecations", + fixture_common_iib_op_args + ["--operator-package", "operator-1", "--deprecation-schema", '{"a": "b"}'], + { + "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", + }, + ) as entry_func: + entry_func() + assert fixture_pushcollector.items == [operator_1_push_item_ad_pending, operator_1_push_item_ad] + add_deprecations_mock_calls_tester( + fixture_iib_client, + fixture_iib_krb_auth, + ) + + +@mock.patch("pubtools.iib.iib_ops.print_error_message") +def test_add_deprecations_cli_error( + mock_print_error_message, + fixture_iib_client, + fixture_iib_krb_auth, + fixture_common_iib_op_args, + fixture_pushcollector, +): + fixture_iib_client.return_value.add_deprecations.side_effect = ( + lambda *args, **kwargs: IIBBuildDetailsModel.from_dict( + fake_tm.setup_task( + *args, + **dict( + list(kwargs.items()) + + [("state_seq", ("in_progress", "failed")), ("op_type", "add-deprecations")] + ) + ) + ) + ) + with setup_entry_point_cli( + ("pubtools_iib", "console_scripts", "pubtools-iib-add-deprecations"), + "pubtools-iib-add-deprecations", + fixture_common_iib_op_args + ["--operator-package", "operator-1", "--deprecation-schema", '{"a": "b"}'], + { + "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", + }, + ) as entry_func: + try: + entry_func() + assert False, "Should have raised SystemError" + except SystemExit: + pass + + assert fixture_pushcollector.items == [ + operator_1_push_item_ad_pending, + operator_1_push_item_ad_notpushed, + ] + + mock_print_error_message.assert_called_once_with( + "https://iib-server/api/v1/builds/task-11" + ) + + +def test_add_deprecations_py( + fixture_iib_client, + fixture_iib_krb_auth, + fixture_common_iib_op_args, +): + with setup_entry_point_py( + ("pubtools_iib", "console_scripts", "pubtools-iib-add-deprecations"), + { + "OVERWRITE_FROM_INDEX_TOKEN": "overwrite_from_index_token", + }, + ) as entry_func: + retval = entry_func(["cmd"] + fixture_common_iib_op_args + ["--operator-package", "operator-1", "--deprecation-schema", '{"a": "b"}']) + + assert isinstance(retval, IIBBuildDetailsModel) + + add_deprecations_mock_calls_tester( + fixture_iib_client, + fixture_iib_krb_auth, + ) + + def test_invalid_op(fixture_common_iib_op_args): try: _iib_op_main((), "invalid-op") diff --git a/tests/utils.py b/tests/utils.py index 165a825..e870c56 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -12,8 +12,9 @@ def _gen_task_id(self): def setup_task( self, index, - map_or_op, - arches, + bundles=None, + operators=[], + arches=None, binary_image="binary-image", overwrite_from_index=False, overwrite_from_index_token=None, @@ -22,6 +23,8 @@ def setup_task( build_tags=None, deprecation_list=None, check_related_images=None, + deprecation_schema=None, + operator_package=None, ): tid = self._gen_task_id() self.task_state_seq[tid] = list(state_seq) @@ -31,7 +34,7 @@ def setup_task( "state_reason": "state_reason", "state_history": [], "from_index": index, - "bundles": map_or_op, + "bundles": bundles, "from_index_resolved": index + "-resolved", "binary_image": binary_image, "binary_image_resolved": binary_image + "-resolved", @@ -44,20 +47,24 @@ def setup_task( "batch": 123, "updated": "2020-05-26T19:33:58.759687Z", "user": "tbrady@DOMAIN.LOCAL", - "removed_operators": ["operator-%s" % k for k in map_or_op], + "removed_operators": [k for k in operators], "organization": None, "omps_operator_version": {}, "distribution_scope": "", "build_tags": build_tags, "deprecation_list": [] if not deprecation_list else deprecation_list, "check_related_images": check_related_images, + "deprecation_schema_url": "link/to/deprecation/schema", + "operator_package": operator_package, } if op_type == "rm": self.tasks[tid]["request_type"] = "rm" if op_type == "add": self.tasks[tid]["request_type"] = "add" - self.tasks[tid]["bundle_mapping"] = {"operator-1": map_or_op} + self.tasks[tid]["bundle_mapping"] = {"operator-1": bundles} + if op_type == "add-deprecations": + self.tasks[tid]["request_type"] = "add-deprecations" return self.tasks[tid]