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..32caa5b16 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 """
@@ -489,6 +489,10 @@ def generate_build_config(cls, copr, chroot_id):
repos.extend(cls.get_additional_repo_views(copr.repos_list, chroot_id))
repos.extend(cls.get_additional_repo_views(chroot.repos_list, chroot_id))
+ repo_priority = copr.repo_priority
+ for repo in repos:
+ repo["priority"] = repo_priority or DEFAULT_COPR_REPO_PRIORITY
+
config_dict = {
'project_id': copr.repo_id,
'additional_packages': packages.split(),
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_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/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)