Add priority-based matching of repository identifiers when posting changes.

Review Request #11127 — Created Aug. 7, 2020 and submitted — Latest diff uploaded


Review Board


Part of the process of posting a change for review is taking the
provided repository identifier (a primary key, name, path, or mirror
path) and fetching the associated repository. If there's a single
repository that matches the identifier against one of those fields, we
use it, but if multiple entries are returned, we tell the client to be
more specific.

There are, however, complex cases out there where multiple repositories
may be returned, each matching a different field against that
identifier. This can happen with archived/hidden repositories, or in
setups trying to transition/consolidate repositories to new central
repositories by setting the repository's name to the same value as
another repository's path.

This change improves the lookup by adding priority-based matching. If
the lookup results in multiple possible repositories, we try to choose a
single one by looking for the following:

  1. Is there only one repository that's visible?
  2. Is there a single repository that has a name matching the identifier?
  3. Is there a single repository that has a path matching the identifier?
  4. Is there a single repository that has a mirror path matching the

Each of those criteria is checked, one-by-one, in order. If any
repository passes that criteria, it will be returned. Otherwise, we
eventually return the same error we did before.

While most setups will never have to go through the priority-based
matching steps, those that do won't see any performance penalty. This
change does not introduce any new SQL queries.

The matching is implemented as Repository.objects.get_best_match(),
allowing the same rules to be applied in queries outside of the API.

Unit tests pass.

Confirmed this fix in a complex production environment. Verified it
solved a "multiple repositories returned" error in their use case.