Support expanded SVN keywords in files and diffs for Beanstalk.

Review Request #10646 — Created July 24, 2019 and submitted — Latest diff uploaded

Information

Review Board
release-3.0.x
aee8b50...

Reviewers

Subversion has support for expanding SVN keywords (like $Id) into
values, and whether a file or a diff contains an expanded form is up to
the value of the svn:keywords property at the time when the file/diff
was fetched or generated, and any discrepency could cause problems when
applying patches. To avoid this problem, our Subversion support fetches
the keywords and collapses them when fetching files or when normalizing
patches.

This only worked for standalone repositories, though, and didn't work in
the case of Beanstalk. In fact, it outright broke. Patch normalization
would attempt to access the Subversion repository using the user's API
key, which wasn't supported, and this would cause an error. We also
weren't able to guarantee getting collapsed versions of files out of the
repository (depending on the file content and svn:keywords at the time
when the file was committed).

Fortunately, to help address this, the Beanstalk team recently gave us
an API to fetch a file's properties on Subversion without needing any
direct access to the repository. This change makes use of this during
both file fetching and patch normalization.

To actually do the work of collapsing, the keyword collapsing code that
used to live within the SVNTool client class has been made available
in a more public utility function, along with all the aliases and other
state needed for it to operate. A new function was also introduced that
checks a file's content to see if it has expanded keywords, helping us
avoid unnecessary lookups.

Hosting services have also gained the ability to normalize patches.
Previously, this was only available in SCMTool, but now a new
Repository.normalize_patch() will call out to either
HostingService.normalize_patch() or SCMTool.normalize_patch(). By
default, this all ends up calling SCMTool.normalize_patch(), but
Beanstalk's able to override this to apply its keyword fetching and
collapsing for Subversion.

All unit tests pass.

Linked a Beanstalk repository with an API token. Manually tested
uploading a diff to it using a file that returned expanded keywords,
and using a diff that also had (hand-edited) expanded keywords. The
upload was successful, and the diff viewer showed collapsed versions
of all keywords.