There may only be one version of a package in //third_party
. This rule applies
to both different versions of a single package, and forks or separate copies
having different package names under //third_party
. There are several reasons
for this restriction.
(A similar restriction exists for google3 at large; see go/one-version-policy.)
Maintenance
The package owner responsibilities require owners to stay up to date with supported versions. At best, having multiple copies of the code means twice as many locations need to be kept up to date. At worst, a substantial fork needs frequent manual maintenance to integrate changes from new upstream versions into the fork.
Security
Projects almost always apply their security efforts to the latest versions as a matter of resource prioritization. Vulnerability feeds sometimes omit older affected versions for a number of reasons (feed quality, time to test or reproduce, people don’t bother reporting for old versions, ...). Sometimes bugs with security consequences are fixed, but the security impact was unnoticed - so if there is a new version, it's possible that a security relevant code change has been added but without being explicitly flagged as such. Keeping packages up-to-date and avoiding multiple older versions of packages around helps avoid the presence of latent vulnerabilities.
Diamond Dependencies
The transitive dependencies of the google3 build system mean that if there are two versions present, eventually someone will try to build a project that depends on both versions. Untangling this after the fact can be very time consuming. Worse, it can stop a project dead that was not involved in submitting either version.
Example of how a project breaks (A→B means A "depends on" B):
Now suppose that:
- FooV2 is added to third_party and made the "default" version, and
- Project C starts using FooV2 (and correctly selects the default V2)
Project A just broke. It depends on two different versions of Foo
and will
select a random one at runtime.
Both Project A and Project C followed the rules, yet one of them now needs to stop and resolve the multiple version issue. Depending on the upgrade and possibly chaining version issues, this can take days or weeks. In C++ this shows up as a static link failure. In Java, this shows up as both versions of Foo being present on project A's classpath and a random version being used at runtime.
In short, google3 depends on there being exactly one version of every dependency.
When we allowed versioned directories (.../v1_20/...
) we found people would
think it was okay to have multiple versions. This is why we have since changed
the policy and don't even allow versioned directories (except for Java and
Haskell, which have special infrastructure in place for this kind of thing).
Exceptions
Temporary <1 month
Sometimes it is useful to temporarily have two versions in order to migrate all of google3 to a single new version.
File a request. If it's straightforward, you don't have to provide a doc; just provide details about how the migration is going to work in the bug. We may request a doc in some cases.
If you are using the standard versioning format, including type:VERSIONS in the parent METADATA file, go ahead and start working! Don't wait for a response on the bug.
Exceptions <1 month are always approved. We use the bug for tracking purposes.
Temporary >1 month
Some transitions take longer.
Create a doc describing your plan to migrate everyone to your version and remove the duplicate. Include a reasonable time and staffing estimate. This is usually one quarter for software projects and two quarters for hardware projects, but it can vary based on context.
Get the doc signed off by your director.
File a request. Link to the document and cc your director.
Wait for approval on that bug before you proceed.
Permanent
We rarely grant permanent exceptions to the one version policy. It's part of the maintainability tax for benefitting from google3. If you think you need one, you can file a request.
Example of a short term exception plan
If you're looking for guidance on how to execute a migration during a short-term exception, you can reach out to the third party team. Here is one example of how you could do it (but YMMV):
Add the new version but with locked-down visibility so no targets are using it.
Prepare a CL that updates forwarding targets to point to the new version. Run Presubmit global presubmit.
If there are easy fixes to be made, make them in that CL.
Assess. Contact callers and ask them to help. Come up with a plan.
If the CL from step (3) is large, break it into two pieces: one that updates forwarding targets to point to the new version and makes broken callers point explicitly to the old version, and one that updates those callers to use the unversioned target again. Use go/rosie to shard out the second piece (see also go/lsc).
If something unforeseen happens and it's necessary to roll back after having started the rosie change, then create separate rollback CLs (or get global approval).
Documentation
Please document any one-version exceptions (whether temporary or permanent) in the METADATA file in the directory containing the versioned packages.
The METADATA file should contain type:VERSIONS
and a
multiple_versions
field in the third_party
section.:
For example:
third_party {
type: VERSIONS
multiple_versions {
type: TEMPORARY
approval: "b/12345 or other approval"
}
}