From 3e4f3d4d3ab6ac0fc904ccb7aea5baae72230d99 Mon Sep 17 00:00:00 2001 From: Jiri Kyjovsky Date: Fri, 19 May 2023 13:40:34 +0200 Subject: [PATCH] frontend, cli, python: Add priority=X to repo config This allows users to set priority of their repository via frontend page or copr-cli. This priority value sets the `priority=X` value in repo confid in /etc/yum.repos.d/_copr:*repo --- cli/copr_cli/main.py | 8 ++++++ cli/tests/test_cli.py | 2 ++ .../7d9f6f921fa0_add_repo_priority_field.py | 25 +++++++++++++++++++ frontend/coprs_frontend/coprs/constants.py | 2 ++ frontend/coprs_frontend/coprs/forms.py | 14 ++++++++++- .../coprs/logic/complex_logic.py | 11 +++++++- frontend/coprs_frontend/coprs/models.py | 11 ++++++++ .../coprs/templates/coprs/_coprs_forms.html | 5 ++++ .../views/apiv3_ns/apiv3_project_chroots.py | 2 +- .../coprs/views/apiv3_ns/apiv3_projects.py | 2 ++ .../coprs/views/apiv3_ns/schema.py | 6 +++++ .../coprs/views/backend_ns/backend_general.py | 1 + .../coprs/views/coprs_ns/coprs_general.py | 3 +++ .../tests/test_apiv3/test_projects.py | 7 ++++-- .../tests/test_logic/test_complex_logic.py | 2 ++ python/copr/v3/proxies/project.py | 8 ++++-- 16 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 frontend/coprs_frontend/alembic/versions/7d9f6f921fa0_add_repo_priority_field.py diff --git a/cli/copr_cli/main.py b/cli/copr_cli/main.py index b05cdd079..a07fe7ec8 100644 --- a/cli/copr_cli/main.py +++ b/cli/copr_cli/main.py @@ -481,6 +481,7 @@ def action_create(self, args): appstream=ON_OFF_MAP[args.appstream], runtime_dependencies=args.runtime_dependencies, packit_forge_projects_allowed=args.packit_forge_projects_allowed, + repo_priority=args.repo_priority, ) owner_part = username.replace('@', "g/") @@ -514,6 +515,7 @@ def action_modify_project(self, args): appstream=ON_OFF_MAP[args.appstream], runtime_dependencies=args.runtime_dependencies, packit_forge_projects_allowed=args.packit_forge_projects_allowed, + repo_priority=args.repo_priority, ) @requires_api_auth @@ -1177,6 +1179,9 @@ def setup_parser(): "created for you (as soon as they are available) as rawhide " "chroot forks.")) + parser_create.add_argument("--repo-priority", default=None, + help="Set the priority value of this repository") + create_and_modify_common_opts(parser_create) parser_create.set_defaults(func="action_create") @@ -1244,6 +1249,9 @@ def setup_parser(): "created for you (as soon as they are available) as rawhide " "chroot forks.")) + parser_modify.add_argument("--repo-priority", default=None, + help="Set the priority value of this repository") + create_and_modify_common_opts(parser_modify) parser_modify.set_defaults(func="action_modify_project") diff --git a/cli/tests/test_cli.py b/cli/tests/test_cli.py index 97c887f91..98b7a70c7 100644 --- a/cli/tests/test_cli.py +++ b/cli/tests/test_cli.py @@ -479,6 +479,7 @@ def test_create_project(config_from_file, project_proxy_add, capsys): "appstream": False, "runtime_dependencies": None, "packit_forge_projects_allowed": None, + "repo_priority": None, } assert stdout == "New project was successfully created: http://copr/coprs/jdoe/foo/\n" @@ -575,6 +576,7 @@ def test_create_multilib_project(config_from_file, project_proxy_add, capsys): "appstream": False, "runtime_dependencies": None, "packit_forge_projects_allowed": None, + "repo_priority": None, } assert stdout == "New project was successfully created: http://copr/coprs/jdoe/foo/\n" diff --git a/frontend/coprs_frontend/alembic/versions/7d9f6f921fa0_add_repo_priority_field.py b/frontend/coprs_frontend/alembic/versions/7d9f6f921fa0_add_repo_priority_field.py new file mode 100644 index 000000000..dfaa9eee9 --- /dev/null +++ b/frontend/coprs_frontend/alembic/versions/7d9f6f921fa0_add_repo_priority_field.py @@ -0,0 +1,25 @@ +""" +Add repo priority field + +Revision ID: 7d9f6f921fa0 +Revises: ba6ac0936bfb +Create Date: 2023-05-25 11:05:39.877208 +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '7d9f6f921fa0' +down_revision = 'ba6ac0936bfb' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('copr', sa.Column('repo_priority', sa.Integer(), nullable=True)) + + +def downgrade(): + op.drop_column('copr', 'repo_priority') diff --git a/frontend/coprs_frontend/coprs/constants.py b/frontend/coprs_frontend/coprs/constants.py index 4f51c2511..85166a53f 100644 --- a/frontend/coprs_frontend/coprs/constants.py +++ b/frontend/coprs_frontend/coprs/constants.py @@ -4,3 +4,5 @@ BANNER_LOCATION = "/var/lib/copr/data/banner-include.html" + +DEFAULT_COPR_REPO_PRIORITY = 99 diff --git a/frontend/coprs_frontend/coprs/forms.py b/frontend/coprs_frontend/coprs/forms.py index 889d82bdc..22ed3b656 100644 --- a/frontend/coprs_frontend/coprs/forms.py +++ b/frontend/coprs_frontend/coprs/forms.py @@ -15,13 +15,13 @@ from flask_wtf import Form as FlaskForm from coprs import app +from coprs import exceptions from coprs import helpers from coprs import models from coprs.logic.coprs_logic import CoprsLogic, MockChrootsLogic from coprs.logic.users_logic import UsersLogic from coprs.logic.dist_git_logic import DistGitLogic from coprs.logic.complex_logic import ComplexLogic -from coprs import exceptions from wtforms import ValidationError @@ -655,6 +655,18 @@ class CoprForm(BaseForm): filters=[StringListFilter(), StripUrlSchemaListFilter()], validators=[wtforms.validators.Optional()],) + repo_priority = wtforms.IntegerField( + "The priority value of this repository", + description="""The priority value of this repository, default is 99. If there is more than one candidate + package for a particular operation, the one from a repo with the lowest priority value is + picked, possibly despite being less convenient otherwise (e.g. by being a lower version).""", + render_kw={"placeholder": "Optional - integer, e.g. 22"}, + validators=[ + wtforms.validators.Optional(), + wtforms.validators.NumberRange(min=1)], + default=None, + ) + @property def errors(self): """ diff --git a/frontend/coprs_frontend/coprs/logic/complex_logic.py b/frontend/coprs_frontend/coprs/logic/complex_logic.py index 9a77d5da1..4c1007298 100644 --- a/frontend/coprs_frontend/coprs/logic/complex_logic.py +++ b/frontend/coprs_frontend/coprs/logic/complex_logic.py @@ -14,6 +14,7 @@ from coprs import models from coprs import exceptions from coprs import cache +from coprs.constants import DEFAULT_COPR_REPO_PRIORITY from coprs.exceptions import ObjectNotFound, ActionInProgressException from coprs.logic.builds_logic import BuildsLogic from coprs.logic.batches_logic import BatchesLogic @@ -456,7 +457,6 @@ def create_object(self, clazz, from_object, exclude=list()): class BuildConfigLogic(object): - @classmethod def generate_build_config(cls, copr, chroot_id): """ Return dict with proper build config contents """ @@ -486,6 +486,15 @@ def generate_build_config(cls, copr, chroot_id): "name": "Copr buildroot", }) + # None value of the priority won't show in API + if copr.repo_priority in [None, DEFAULT_COPR_REPO_PRIORITY]: + repo_priority = None + else: + repo_priority = copr.repo_priority + + for repo in repos: + repo["priority"] = repo_priority + repos.extend(cls.get_additional_repo_views(copr.repos_list, chroot_id)) repos.extend(cls.get_additional_repo_views(chroot.repos_list, chroot_id)) diff --git a/frontend/coprs_frontend/coprs/models.py b/frontend/coprs_frontend/coprs/models.py index 038534b47..915253cd6 100644 --- a/frontend/coprs_frontend/coprs/models.py +++ b/frontend/coprs_frontend/coprs/models.py @@ -388,6 +388,17 @@ class _CoprPublic(db.Model, helpers.Serializer): # allowed to build in this Copr via Packit packit_forge_projects_allowed = db.Column(db.Text) + # priority=NUMBER in repo configs + repo_priority = db.Column(db.Integer, nullable=True) + + @validates("repo_priority") + def validate_repo_priority(self, _, value): + """Checks whether priority value is correct""" + if value < 1: + raise ValueError("Repo priority can't be lower than 1") + + return value + class _CoprPrivate(db.Model, helpers.Serializer): """ diff --git a/frontend/coprs_frontend/coprs/templates/coprs/_coprs_forms.html b/frontend/coprs_frontend/coprs/templates/coprs/_coprs_forms.html index 6430624cd..004605e5a 100644 --- a/frontend/coprs_frontend/coprs/templates/coprs/_coprs_forms.html +++ b/frontend/coprs_frontend/coprs/templates/coprs/_coprs_forms.html @@ -156,6 +156,11 @@

{{ counter('instructions') }}. Other options

placeholder='Optional', info='Delete the project after the specfied period of time (empty = disabled)') }} + {{ render_field(form.repo_priority, + class="short-input-field", + placeholder='Optional', + info='Set the priority value of this repository. Defaults to 99.') }} + {{ render_field(form.isolation, placeholder='default') }} {{ render_bootstrap_options(form) }} diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py index 0fe3f9ab1..d386e1181 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py @@ -95,7 +95,7 @@ class BuildConfig(Resource): parser = project_chroot_parser() @apiv3_project_chroots_ns.expect(parser) - @apiv3_project_chroots_ns.marshal_with(project_chroot_build_config_model) + @apiv3_project_chroots_ns.marshal_with(project_chroot_build_config_model, skip_none=True) def get(self): """ Get a build config diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py index 1b4b8b389..dd5e99133 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py @@ -39,6 +39,7 @@ def to_dict(copr): "appstream": copr.appstream, "packit_forge_projects_allowed": copr.packit_forge_projects_allowed_list, "follow_fedora_branching": copr.follow_fedora_branching, + "repo_priority": copr.repo_priority, } @@ -162,6 +163,7 @@ def _form_field_repos(form_field): runtime_dependencies=_form_field_repos(form.runtime_dependencies), appstream=form.appstream.data, packit_forge_projects_allowed=_form_field_repos(form.packit_forge_projects_allowed), + repo_priority=form.repo_priority.data, ) db.session.commit() except (DuplicateException, diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/schema.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/schema.py index 1c3c83947..28319a561 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/schema.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/schema.py @@ -100,6 +100,11 @@ example="nspawn", ) +repo_priority_field = Integer( + description="The priority value of this repository. Defaults to 99", + example=42, +) + enable_net_field = Boolean( description="Enable internet access during builds", ) @@ -311,6 +316,7 @@ "id": String(example="copr_base"), "name": String(example="Copr repository"), "module_hotfixes": module_hotfixes_field, + "priority": repo_priority_field, } repo_model = api.model("Repo", repo_schema) diff --git a/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py b/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py index 2be533678..59a11c877 100755 --- a/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py +++ b/frontend/coprs_frontend/coprs/views/backend_ns/backend_general.py @@ -165,6 +165,7 @@ def get_build_record(task, for_backend=False): "isolation": task.build.isolation, "fedora_review": task.build.copr.fedora_review, "appstream": bool(task.build.appstream), + "repo_priority": task.build.copr.repo_priority }) copr_chroot = CoprChrootsLogic.get_by_name_safe(task.build.copr, task.mock_chroot.name) diff --git a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py index 88325a150..64365c9e3 100644 --- a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py +++ b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py @@ -282,6 +282,7 @@ def copr_new(username=None, group_name=None): isolation=form.isolation.data, appstream=form.appstream.data, packit_forge_projects_allowed=form.packit_forge_projects_allowed.data, + repo_priority=form.repo_priority.data ) db.session.commit() @@ -554,6 +555,8 @@ def process_copr_update(copr, form): copr.isolation = form.isolation.data copr.appstream = form.appstream.data copr.packit_forge_projects_allowed = form.packit_forge_projects_allowed.data + copr.repo_priority = form.repo_priority.data + if flask.g.user.admin: copr.auto_prune = form.auto_prune.data else: diff --git a/frontend/coprs_frontend/tests/test_apiv3/test_projects.py b/frontend/coprs_frontend/tests/test_apiv3/test_projects.py index 800211cdc..2a8a9cd6c 100644 --- a/frontend/coprs_frontend/tests/test_apiv3/test_projects.py +++ b/frontend/coprs_frontend/tests/test_apiv3/test_projects.py @@ -77,7 +77,7 @@ def test_update_copr_api3(self): # testing method! already_tested = set([ "delete_after", "build_enable_net", "auto_createrepo", "repos", - "runtime_dependencies", "packit_forge_projects_allowed" + "runtime_dependencies", "packit_forge_projects_allowed", "repo_priority" ]) # check non-trivial changes @@ -91,6 +91,7 @@ def test_update_copr_api3(self): assert old_data["auto_prune"] is True assert old_data["follow_fedora_branching"] is True assert old_data["packit_forge_projects_allowed"] == "" + assert old_data["repo_priority"] is None self.api3.modify_project( "test", delete_after_days=5, enable_net=True, devel_mode=True, repos=["http://example/repo/", "http://another/"], @@ -100,7 +101,8 @@ def test_update_copr_api3(self): "https://github.com/packit/ogr", "github.com/packit/requre", "http://github.com/packit/packit" - ] + ], + repo_priority=13, ) new_data = self._get_copr_id_data(1) delete_after = datetime.datetime.now() + datetime.timedelta(days=5) @@ -113,6 +115,7 @@ def test_update_copr_api3(self): old_data["bootstrap"] = "default" old_data["packit_forge_projects_allowed"] = "github.com/packit/ogr\ngithub.com/packit/requre\ngithub.com" \ "/packit/packit" + old_data["repo_priority"] = 13 assert old_data == new_data old_data = new_data diff --git a/frontend/coprs_frontend/tests/test_logic/test_complex_logic.py b/frontend/coprs_frontend/tests/test_logic/test_complex_logic.py index 6a1e7ff55..d5ecc3b1f 100644 --- a/frontend/coprs_frontend/tests/test_logic/test_complex_logic.py +++ b/frontend/coprs_frontend/tests/test_logic/test_complex_logic.py @@ -7,6 +7,7 @@ from coprs import models, helpers from copr_common.enums import ActionTypeEnum +from coprs.constants import DEFAULT_COPR_REPO_PRIORITY from coprs.logic.actions_logic import ActionsLogic from coprs.logic.complex_logic import ( BuildConfigLogic, @@ -252,6 +253,7 @@ def test_generate_build_config_with_dep_mistake(self): "name": "Copr repository", "baseurl": "http://copr-be-dev.cloud.fedoraproject.org" "/results/user1/foocopr/fedora-18-x86_64/", + "priority": DEFAULT_COPR_REPO_PRIORITY, } build_config = bcl.generate_build_config(self.c1, "fedora-18-x86_64") assert build_config["repos"] == [main_repo] diff --git a/python/copr/v3/proxies/project.py b/python/copr/v3/proxies/project.py index e22642757..89b062ea2 100644 --- a/python/copr/v3/proxies/project.py +++ b/python/copr/v3/proxies/project.py @@ -71,7 +71,8 @@ def add(self, ownername, projectname, chroots, description=None, instructions=No auto_prune=True, use_bootstrap_container=None, devel_mode=False, delete_after_days=None, multilib=False, module_hotfixes=False, bootstrap=None, bootstrap_image=None, isolation=None, follow_fedora_branching=True, - fedora_review=None, appstream=False, runtime_dependencies=None, packit_forge_projects_allowed=None): + fedora_review=None, appstream=False, runtime_dependencies=None, packit_forge_projects_allowed=None, + repo_priority=None): """ Create a project @@ -139,6 +140,7 @@ def add(self, ownername, projectname, chroots, description=None, instructions=No "appstream": appstream, "runtime_dependencies": runtime_dependencies, "packit_forge_projects_allowed": packit_forge_projects_allowed, + "repo_priority": repo_priority, } _compat_use_bootstrap_container(data, use_bootstrap_container) @@ -157,7 +159,8 @@ def edit(self, ownername, projectname, chroots=None, description=None, instructi auto_prune=None, use_bootstrap_container=None, devel_mode=None, delete_after_days=None, multilib=None, module_hotfixes=None, bootstrap=None, bootstrap_image=None, isolation=None, follow_fedora_branching=None, - fedora_review=None, appstream=None, runtime_dependencies=None, packit_forge_projects_allowed=None): + fedora_review=None, appstream=None, runtime_dependencies=None, packit_forge_projects_allowed=None, + repo_priority=None): """ Edit a project @@ -223,6 +226,7 @@ def edit(self, ownername, projectname, chroots=None, description=None, instructi "appstream": appstream, "runtime_dependencies": runtime_dependencies, "packit_forge_projects_allowed": packit_forge_projects_allowed, + "repo_priority": repo_priority, } _compat_use_bootstrap_container(data, use_bootstrap_container)