Dart

This describes Dart-specific guidance for checking code into //piper/third_party/dart.

IMPORTANT: Read go/thirdparty first. For Dart-specific questions, email emailremoved@.

General policies

Preserving licenses

Third-party licenses must be preserved on generated code. There are several build rules to support Dart in google3. The dart_application rule compiles Dart to JavaScript. This rule automatically includes the text of any LICENSE file included in its (or its dependencies') srcs lists in the resulting JavaScript.

Do not approve CLs unless you are the last third-party-* reviewer

When multiple reviewers are auto-assigned to a brand-new //piper/third_party package, only the last reviewer to LGTM should 'g4 approve' the CL. Other reviewers should LGTM and then defer to the remaining auto-assigned reviewers.

Adding code to google3

All new packages must be approved by someone in emailremoved@. For all changes that involve an OWNERS file (which should include all new packages) third-party-removed will be added to reviewers automatically. Approval is not required from anyone other than the OWNERS for updates.

Criteria for importing packages

Code imported to google3 is expected to meet a similar quality bar to code written directly in google3, although no particular extensive code review is required. The third-party-removed members may request that a package not be imported if it appears risky. Imported code must:

  • Have tests that can run and pass in google3.
  • Avoid antipatterns like debug print statements.
  • Not have obvious signs of quality issues.
  • Be compatible with the current Dart SDK.

We strongly prefer that:

  • The package uses code reviews for contributions.
  • The code does not need patches to work in google3.
  • The package has recent updates.
  • The author is willing to accept contributions from googlers.
  • The package demonstrates appropriate use of semver

Packages which don't meet these criteria may be refused by the Dart reviewer. For exceptions see temporary unsupported packages.

NOTE: If a package is Flutter owned, you will see "Flutter Team" as the author on the pub listing. If it is Dart owned, you will see "Dart Team". These packages are easier to bring into Google because we own and maintain them.

We require that there are at least 2 OWNERS for every package. These owners are responsible for syncing new versions of the package, including working with teams to update internal code using the package when there are breaking changes. If you are not comfortable taking responsibility for usage outside of your project you can make the package private in blaze and request that other projects wishing to add a dependency add some representation in OWNERS.

Requirements for maintaining packages

We do not allow packages to go "stale" in google3, as packages are updated and published they should be rolled into google3. It is the responsibility of the OWNERS to roll packages, and in cases of breaking changes help teams to migrate. The latest version published on pub is the authoritative version. It is allowed to have package versions in google3 that are newer than the latest published package. This is especially useful for testing and validating the code against a large code base before publishing. A package is stale if it is 1 major or feature (minor) version behind, or if it is 2 patch versions behind.

We do not allow forking packages. A package may have google3 specific patches in exception cases to allow for differences in the google3 environment (for instance differences in the working directory when tests are running). Copybara patch files are strongly preferred for managing google3 changes. If a copybara patch is not feasible the change must be documented in the local_modifications field of the METADATA file. We do not allow patches for things like reverting breaking changes indefinitely.

Maintaining packages often means being able to submit code to upstream repo (since forking is not allowed). We strongly recommend that the OWNERS of the package become collaborators in the upstream repo as well. Most repo owners are delighted to partner up with a Googler or two, so reach out! Their emails are typically available on the pub page of the project.

You can use the following draft as an email. > Hi *repo_owner*, > > We are *insert_team* within Google. Recently, there has been a lot of interest > in one of your Flutter/Dart packages. So, we are planning on bringing > *package_name* to our development environment. > > However, per policy, we need multiple owners, preferably some Googlers, on any > such repo so that we can get PRs reviewed and submitted in a timely manner. > For instance, we would not want critical PRs to be delayed because you go on > vacation and can't review the code. On the upside, your plugin will be much > more feature rich and the entire community will benefit. > > Alternatively, we could fork the code but I am not a big fan of that since you > end up with multiple plugins all doing the same thing and it isn't clear which > one to choose for the end user. I wanted to reach out to you and ask you to > consider a partnership instead. > > If you accept, please add *github_alias_of_googler_1* and > *github_alias_of_googler_2* as a reviewer with merge privileges. > > Please let me know as soon as you can.

Temporary Unsupported Packages

Packages that do not meet the google3 quality bar may be useful and viable after some contributions are made to improve the code health. For instance a team may decide to contribute tests. In order to allow experimentation and give teams a chance to evaluate whether an upstream contribution is worth pursuing, a package may be brought in with a 6 month window to either raise the quality of the package or delete it from google3.

Unsupported packages may not block Dart SDK or other third party package rolls. We won't roll back a CL that breaks an unsupported package.

Process:

  • Restrict the blaze visibility of the package to only the team with representation in the OWNERS file. Add a note next to the visibility list that the package is unsupported and may be removed if it can't be improved.
  • In the CL description include the statement "This package does not meet the google3 quality bar, it will be improved or removed by <date>".
  • File a bug against a component appropriate for the project which will use the new package and CC emailremoved@. Assign to go/bugjuggler with a 5 month delay. After 5 months the bug should be assigned to the author bringing in the package. Reference this bug in the CL bug field.
  • At anytime during the 6 month window if the package can be brought up to google3 standards it may "graduate" to a community supported package.
  • After the 6 month period the package can be reviewed again, if it does not meet the quality bar it must be removed without exception.

After graduating to a community supported package, the visibility restriction may be lifted at the discretion of the teams with representation in OWNERS.

Process for importing packages

WARNING: The process for bringing a new Flutter plugin is different as it contains native code in addition to Dart code. Please see go/new-flutter-plugin instead of following instructions below.

  • Dart source code must be placed in //third_party/dart/<packagename> where <packagename> matches the package name on http://linkremoved/. The resolution for package: URIs relies on this directory name.
  • The layout of code within //third_party/dart/<packagename> must be identical to the pub package layout.
  • Every new package should be added in a separate CL (see go/pristinecopy)

Pull in the code using one of the following tools.

Copybara (preferred tool):

Follow Copybara's Getting Started (go/copybara/userdoc/getting_started.md) if you have not used Copybara before, which basically boils down to:

alias copybara='/path/to/.../copybara'

Then migrate new commits from GitHub to google3:

copybara third_party/dart/<package>/copy.bara.sky

GitHub:

blaze build //dart/tools:pullfromgit && blaze-bin/dart/tools/pullfromgit --package=<package> --version=<version> [--new_package]

Pub:

Please use only if GitHub source is not available or not tagged. SecOps prefers a GitHub source to a pub.dev source.

blaze build //dart/tools:pullfrompub && blaze-bin/dart/tools/pullfrompub --package=<package> --version=<version> [--new_package]

After pulling in the code:

  1. Check LICENSE and ensure we can use the code. See go/thirdpartylicenses for details.

  2. Fix inconsistencies between the public package and go/thirdparty rules. For example, if a package has a license in LICENSE.txt, which goes against the rule listed that the file must be named LICENSE, rename it.

    mv LICENSE.txt LICENSE
    g4 add LICENSE; g4 revert LICENSE.txt
    
  3. Do not fix other problems, even if this means unit tests do not pass. The first commit should be the version of the code as it was downloaded (go/pristinecopy).

  4. Create a BUILD file.

    1. Add a dart_library target that includes all srcs in lib/, and a license attribute indicating the LICENSE file.

      dart_library(
          name = "lzma",
          srcs = glob(["lib/**/*"]),
          license_files = ["LICENSE"],
          deps = [...],
       )
      

      If the package uses any platform restricted imports (io, ui, html, js, mirrors) add a required_libs argument. See go/dart-required-libs

    2. Ensure the licenses BUILD extension has the correct value(s).

    3. Add tests with dart_vm_test, dart_browser_test, or flutter_test_suite so the unit tests run in our Presubmit queues. Sometimes this would require modifying the source, which should not be done (per go/pristinecopy). If that is the case, add a TODO and fix in a subsequent CL.

    4. Run buildifier -a -v

  5. Create an OWNERS file with at least 2 full time googlers who are willing to commit to maintaining the package.

Updating an existing package from Git or Pub

General guidance

  • It (probably) won't be in google3 unless someone is using it, and it is your responsibility to ensure that the update does not break any tests. See Step-By-Step Instructions below.

  • Don't use NO_SQ= or g4 submit -f to submit a CL with broken tests. If a presubmit reveals a small number of already failing tests unrelated to your CL, or fails due to flaky tests, you may use SKIP_CLIENT_TESTS= with a brief description of why it is needed.

  • In contrast to new packages, batching together multiple package updates is allowed when packages are coupled.

Step-by-step instructions

We’ll use the "args" package as an example

  1. Review the CHANGELOG to familiarize yourself with any changes that could break existing code.
  2. Make any necessary preemptive changes. go/using-rosie is your friend. Don’t forget replace_string!
  3. Create a client:

    mkclient -f dart_update
    
  4. Take a look at the pullfromgit.py and pullfrompub.py utilities:

    dart/tools/pullfromgit.py --helpshort
    

    or

    dart/tools/pullfrompub.py --helpshort
    
  5. Use pullfromgit.py or pullfrompub.py to automatically update the source:

    dart/tools/pullfromgit.py --package=args --version=0.12.2+2
    

    or:

    dart/tools/pullfrompub.py --package=args --version=0.12.2+2
    
  6. Repeat for any other packages.

  7. If dependencies or dev_dependencies have been added or removed in pubspec.yaml, mirror those changes in BUILD.

  8. Make sure you're not breaking anything by checking (in order):

    1. Unit tests (if present): blaze test //third_party/dart/args/...
    2. (Optional) dart_lang & dart_lang.presubmit Presubmit queues:

      presubmit -c $CL -p dart_lang,dart_lang.presubmit
      

      The next step (global presubmit) will also run these tests, but they run much faster here than during global. If you believe the changes may cause breakages, it may be worth completing this step.

    3. Global presubmit. See http://linkremoved/ for details:

      presubmit --train -c $CL -p all
      
  9. If your change breaks targets in google3:

    1. Generate a new patch CL with the fixes (see go/using-rosie).
    2. Run a global presubmit to verify your fix is good.
    3. Send it out to the appropriate owners:

      1. For small CLs, click the "suggest reviewers" dropdown on the right hand side of the Reviewers field. If you prefer the command-line:

        g4 findreviewers -c $CL
        
      2. For large CLs, see go/rosie. Rosie will shard your CL, run tests (if requested), select appropriate reviewers and auto-submit your CLs for you.

  10. Create and mail the CL. If unfamiliar, see one of:

    1. g4 help {change, mail, submit}
    2. Developer Workflow Codelab.
    3. g4 commands.

Examples

  • changelist ...230

What about third_party/dart_src?

third_party/dart_src was created to support internal development of packages that do not adhere to the conventions of Dart pub packages. Parts of these directories are published as pub packages and synced to open source repos after transforming the code.

NOTE: Code that is developed in third_party/dart_src should not have a version in third_party/dart. Please adhere to the one version policy, see go/oneversion.

Dependencies on third_party/dart_src packages

If your internal application has a dependency on code in third_party/dart_src, that is fine. Just depend on the BUILD files you need and write your Dart import statements like any other internal Dart file.

Example: import 'package:third_party.dart_src.foo.bar.baz/qux.dart';

If your project has a dependency on any code in third_party/dart_src, and you intend to publish your code as open source, let's talk. Please see below.

Developing new public packages

The common case for most packages is to be located in third_party/dart. Place your code in third_party/dart_src if:

  • Internal development is demonstrably hindered by the need to adhere to Dart pub package conventions.
  • Code that is open source will have dependencies on code in third_party/dart_src.

We are developing a simple and maintainable process for syncing code between third_party/dart_src and open source repos like GitHub. Tooling is under development to automate this process using go/copybara.