In many callers, this allows us to remove special error handling code:
problems will propagate as UnprocessableEntityExceptions with helpful
messages. The main exception is in AccountsCollection, which is used to
parse users out of URLs (as opposed to, say, JSON inputs). In this case
the correct behavior is to wrap the exception in
ResourceNotFoundException, or AuthException in the case of "self".
The one place that gets more ugly is ReviewerAdder, where we need to
propagate the exception message for a NOT_FOUND result and combine that
with the hard-coded error message when a group is missing. This produces
a somewhat unnecessarily verbose message. The idea is that this
AccountResolver series is a prerequisite for rewriting ReviewerAdder,
which will reduce this ugliness.
Change-Id: I99c03df3da853cba7958bc027d0f67a0320c9e5a
In the old AccountResolver, the "parse" methods support "self", but the
"find" methods didn't. This meant that callers using "find" either
needed to remember to special case this string, as in
ChangeQueryBuilder, or else they wouldn't get the special behavior.
Consolidate this logic in one location instead.
The string "self" returns an empty Result set when the user is not
logged in. For callers that need to distinguish this case from other
empty results, add isSelf methods to both Result and
UnresolvableAccountException.
Reuse the resolver logic directly in ChangeQueryBuilder instead of
hand-rolling support for "self". This means we also need to support
"me". Again, the consistency here makes sense: it's odd that "me" was
a synonym for self in the change query syntax but not in the REST API.
(It's still not, yet, but it will be when we finish migrating callers to
AccountResolver2.)
Change-Id: I7113aa7a1e274d63826241757cad0aa10370d5c2
Introduce a subclass of UnprocessableEntityException specific to this
resolver code. Flesh out the error message in the ambiguous and inactive
cases with the list of matching accounts, which is something end users
have wanted for a long time. One reason we weren't able to provide this
before was it was hard to reason about whether the multiple matching
accounts were visible to the calling user. Now that we have stricter
guarantees about visibility in the Result object, we know this is safe
to do.
Unfortunately, producing this exception message requires making Result
non-static so we can pass through the injected AnonymousCowardName. This
means we can't use AutoValue. However, neither downstream consumers nor
tests were depending on any of the niceties of AutoValue. Nor should
they be, really: AccountState is not immutable and doesn't implement
equals.
Rewriting the core search logic to keep track of inactive users makes it
a bit more complicated, and at this point it makes more sense to inline
the trySearch method. The complicated logic is hopefully balanced by
good test coverage.
Remove the Searcher field from Result. This wasn't providing much value
in tests, since the searcher that matched is pretty well identified by
the particular set of accounts that were returned. And now, with
inactive users being combined across searchers, there's not necessarily
a single searcher that identifies the result.
Change-Id: I500fe32ade899d991ade90f90eaf5b8b83224a0d
This method is used in exactly one case: MailUtil, for optionally
parsing accounts out of git identities in special commit footers. Out of
an abundance of caution (and because the new code structure makes it
easy), keep the behavior exactly the same.
However, the long term future of this code is unclear[1]: should we
remove it entirely? Or at least limit the format so it requires
something looking more like a git identity than a random bag of stuff we
pass to the index? It's not clear that this or other potential callers
resolveByNameOrEmail actually understand the current semantics. For that
reason, mark the new method as deprecated.
[1] https://groups.google.com/d/msg/repo-discuss/tIFxY7L4DXk/6wqTK5-UHQAJ
Change-Id: I33470221812e398e80b7265f5fe21e51203ed187
AccountResolver has a mishmash of methods with different resolution
semantics, different disambiguation semantics, and different return
types.
A short, non-exhaustive list of illustrative examples of confusing
things about this class:
* find(String) returns null if there is not exactly one match;
parse(String) throws UnprocessableEntityException.
* The difference between parse(String) and parseId(String) doesn't have
anything to do with IDs, it's that one of them respects account
visibility and the other doesn't. (Pop quiz: which one is which?)
* findAll(String) and findAllByNameOrEmail(String) don't in fact find
*all* matching accounts: some paths short-circuit. For example, if
the input is a number, it will return one result if the number is an
existing account, and zero results otherwise, even though *all*
accounts strictly speaking might include users whose full name
happens to be a numeric string.
* find(String) filters out inactive users, but findAll doesn't.
These issues at best lead to head-scratching and at worst to subtle but
potentially serious bugs like failing to respect account visibility.
What we really need is a more intentionally designed interface. This
change starts a new implementation, temporarily named AccountResolver2;
once it reaches parity with AccountResolver and all callers have been
migrated, it will be renamed.
The main benefit of the new implementation is that it separates the
_searching_ semantics from the _result_ semantics. For a given input, we
always produce a single Result object, which encapsulates zero or more
results. The Result class has several view methods which allow callers
to convert an arbitrarily sized list of AccountStates to another type
that they may find more useful, like a set of Account.Ids or a single,
unique account. This also provides us a single place to produce useful
exception messages when an account is not unique.
The other major change from AccountResolver is that the new
implementation consistently filters out invisible and inactive users.
We'll explain these one at a time.
First, AccountResolver2 never returns accounts that are not visible to
the calling user. The purpose of this class is to parse
end-user-provided strings to accounts in various contexts (REST API
URLs, REST API inputs, search queries). The search semantics are
intentionally somewhat fuzzy specifically because the input is
user-provided. Since it's user-provided, we can safely assume that there
is an end user on the other end for whom we can check visibility. It's
true that some Gerrit code needs to bypass account visibility, but that
code shouldn't use the AccountResolver interface; it should use a
lower-level interface like InternalAccountQuery.
Next, AccountResolver2 almost always filters out inactive users, except
in one specific case: when the input is a number. This reflects our
experience providing support for customers who are very confused when
their REST API operations fail because they specified some account
string that they thought was unique but that actually matched some
inactive accounts. The idea is that in normal usage, users should never
need to care about inactive accounts--it should be as if they don't
exist. In certain administrative contexts, it is necessary to care about
them, for example an admin re-enabling an account. In these contexts, an
admin can figure out the unambiguous account ID, for example by
searching with [-is:active]. This is a slightly backwards-incompatible
change (although the documentation was never clear on what type of
filtering could occur), but based on our experience, the expected
reduction in user confusion and consequent support costs makes the
change worth it. We should also be able to provide a useful exception
message listing inactive accounts, now that we have a common place to
put the logic.
Taken together, the filtering semantics mean that an end user can't
distinguish between the case where AccountResolver2 produces no results
and where it only produced inactive or invisible results. This is
considered a feature.
In terms of implementation, switch to a more declarative style of
defining the search semantics, based around the concept of a single
Searcher matching a single type of input. Searchers are then iterated
over in a loop, separating the definition of lookup semantics from the
precedence and short-circuiting behavior. This implementation allows us
to preserve the previous search implementation quite closely, while
making it crystal-clear what are the list of supported formats, and
where the intent is to short-circuit and where not. It additionally
makes it possible to write small tests of just the looping logic,
without having to build up all the dependencies required to do actual
account resolution.
Change-Id: I08e64c647378a9275e425b68c39122984ee37e77
* stable-2.16:
Index groups with in-memory test
Index projects with in-memory test
Fix loading topics that have unusual characters
Change-Id: Iab74f0539842617c4aeac91dfc083ba620a7c06b
SearchingChangeCacheImpl only returns a fraction of all changes. This
fraction covers most recently modified changes. This is problematic when
users want to fetch a change that is older than what this set covers.
There are Gerrit instances with millions of changes and the concept of
index-backed evaluation doesn't scale to this size. Other concepts
failed and had to be reverted (I447eaeb).
If refs-in-wants on Protocol V2 is used, we can fix the shortcomming by
investigating only a single ref backed by NoteDb.
Change-Id: Ib01492ac58eda4a37086aa3e106be857cfb566e1
* changes:
CreateChange: move code for create change to a method
CreateChange: move code for creating commit message to a method
CreateChange: move logic for getting parent commit to its own method
CreateChange: move logic for getting base change to its own method
CreateChange: move out checks for "merge" field of the ChangeInput
CreateChange: move logic for "isWorkInProgress" to #checkAndSanitizeChangeInput
CreateChange: move permission checks to its own method
CreateChange: move logic for "isPrivate" to #checkAndSanitizeChangeInput
CreateChange: move code for preprocess input to its own method
This is more readable and less error-prone than passing in null for the
IdentifiedUser if the server identity should be used.
This allows AccountsUpdate/GroupsUpdate to use Optional for the
IdentifiedUser internally which makes the internal code nicer.
Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Ie8593b5194a48a21fa85857879197fd7ca9d5908
When running integration tests with in-memory repositories make
sure that they are all indexed in Lucene before starting the tests.
This enables the implementation of tests that can rely on a
consistent projects index to run.
Change-Id: I2e628e4555ed7faa24fff44a0d226b57b5ce9909
This option is used in several places, and deprecating it causes
warnings.
Because change.api.excludeMergeableInChangeInfo is configurable, callers
have no way to reliably request a change without computing mergeability
without specifying the SKIP_MERGEABLE option.
Remove the @Deprecated annotation, and clarify the documentation.
Change-Id: I20fdadbda12f3d7e434d2f61f5a93569a0df3674
* stable-2.16:
ListChildProjects: Make settting recursive option chainable
ListChildProjects: Add limit option
ListChildProjects: Use parent predicate to find child projects
QueryProjects: Make setter methods chainable
Project index: Add parent predicate
ListChildProjectsIT#listChildrenWithLimit is adjusted to use the
ProjectOperations interface.
Change-Id: I185c204f6acbf542f7d80454fe67ce892147473a
Enabling the search by parent enables the rewrite
of the ListChildProjects REST-API that extracts the children
of a project. Using the Lucene index avoids the full scan
of the ProjectCache and thus speedup the extraction and
reduce the JVM heap consumption.
Bug: Issue 10401
Change-Id: I568d6ba0e5a0bff391f57e2357de6d059d77fe5d
Just a small readability improvement. No functional change intended.
The lambdas were found using
git grep -Ovi -e '\([a-z0-9]\+\) -> \1\.[^.]*()[,);]'
Signed-off-by: Jonathan Nieder <jrn@google.com>
Change-Id: I6abc206d555e3215f80e45cdaf180cea0050fcd3
DisallowCreationAndDeletionOfUserBranches no longer applies to user
branches only, but also disallows the creation and deletion of group
branches. Give it a more generic name.
Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: I73d37a59b68d68c062376da114de3762bdd08461
Schema migrations do all their work in the upgrade method. This is the
place where they need to access the arguments. If the arguments are
passed into the constructor, each schema migration must save the
arguments in a local member veriable to make them accessible from the
upgrade method. To save this boilerplate code we now directly pass the
arguments into the upgrade method. This means schema versions don't
need to define any constructor since the default constructor is all that
is needed.
Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Ie35d088bde76c0d11440b073034ecdae8df59a2c
* stable-2.16:
Elasticsearch: Support and use v6.6.0 for testing
Adds <noscript> to PolyGerritIndexHtml.soy
Change-Id: I916e1fdca110f0e958e05ea74e100c9883cc0d30
* stable-2.15:
Elasticsearch: Support and use v6.6.0 for testing
Adds <noscript> to PolyGerritIndexHtml.soy
Change-Id: I93e6121d3fbb97d3f6598131148d50c73db19704
First customer will be the find-owners plugin to get
plugin config parameters in project.config and gerrit.config.
Change-Id: I6bbc3cbad93b31aa8dc36b711ad6d74acef05424
With this and previous commits, code in "CreateChange"
is reorganised for better readability. Each method is
relatively small and mainly serves for one
functionality.
Change-Id: I893e38ee726f245706a5bb266b7c291de40bfbf6
This check is required for the input and can be done before
lots of the above code being executed. Moving it to
rejected early.
Change-Id: I62ed7b18bfa441dc6d7addb06a105069932acd9d
This commit groups those permission checks to a dedicated
method. It also renames "rsrc" to "projectResource" to make
it more readable.
Change-Id: I7b9ed0f9aa3d4af5e3fb1a9d0b9de96455d605a8
The existing #clean method is merged into this new method. More
code for preprocessing will be merged into this method in the
followup methods.
Change-Id: I943708898b2e47c62912fad739fefe8dccdd36fd
filterTagsSeparately was an option to make refs computation faster. It
was used from parts in Gerrit that didn't need this option and wanted
a faster computation. Now that we have restricted tags to be reachable
from refs/heads/* we can remove that extra complexity.
I764e16d introduced this originally.
Change-Id: I6c4a01db77ff9dad93439788100e8a4b090d946a
With the current 'extension' search operator it's possible to find
a) changes that contain at least one file with the given extension,
e.g.: extension:txt
b) changes that contain no file with the given extension,
e.g.: -extension:txt
However sometimes you want to match changes which only contain files of
a given extension, e.g. changes that only touch txt files. This can now
be done with the new 'only_extensions' search operator, e.g.:
only_extensions:txt
It is also possible to specify multiple file extensions. E.g. matching
changes that only touch txt and jpg files can be done by:
only_extensions:jpg,txt
By reversing the 'only_extensions' search operator it is possible to
match changes that not only touch files with certain extensions, e.g.:
-only_extensions:jpg,txt
The order and the case in which the extensions are provided to the
'only_extensions' operator don't matter.
Also extensions can be specified with or without leading '.' (same as
for the 'extension' search operator).
Changes that contain files without file extension can be matched by
including an empty file extension into the file extension list, e.g.:
* changes that only include txt files and files without extension:
only_extensions:,txt
* changes that only contain files without extension:
only_extensions:,
only_extensions:""
Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: I3d2b978ed455f835d1dad2daa920be0b0ec2ae36