Bug 1506267 - Add android-api-lint to automation; r=nalexander
authorAgi Sferro <agi@mozilla.com>
Mon, 19 Nov 2018 16:03:55 +0000
changeset 503440 655a4ddc4212cfcbc835dca5d643af7309573c39
parent 503439 04afa20040846c14349b9015cd0089ec0b0aad85
child 503441 17edafa646aef9ba5f1bb13d5dbff7cba3145700
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnalexander
bugs1506267
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1506267 - Add android-api-lint to automation; r=nalexander Depends on D11821 Differential Revision: https://phabricator.services.mozilla.com/D12166
mobile/android/gradle.configure
mobile/android/mach_commands.py
taskcluster/ci/build/android-stuff.yml
testing/mozharness/configs/builds/releng_sub_android_configs/64_api_lint.py
testing/mozharness/mozharness/mozilla/building/buildbase.py
--- a/mobile/android/gradle.configure
+++ b/mobile/android/gradle.configure
@@ -64,16 +64,42 @@ def gradle_android_build_config():
         ),
         geckoview_example=namespace(
             variant=variant(('withGeckoBinaries',), 'debug'),
         ),
     )
 
 
 @depends(gradle_android_build_config)
+@imports(_from='itertools', _import='imap')
+def gradle_android_intermediates_folder(build_config):
+    '''Path to intermediates classes folder.'''
+    def uncapitalize(s):
+        if s:
+            return s[0].lower() + s[1:]
+        else:
+            return s
+
+    def capitalize(s):
+        # str.capitalize lower cases trailing letters.
+        if s:
+            return s[0].upper() + s[1:]
+        else:
+            return s
+
+    productFlavor = uncapitalize(''.join(imap(capitalize, build_config.geckoview.variant.productFlavors)))
+    buildType = uncapitalize(build_config.geckoview.variant.buildType)
+
+    return "gradle/build/mobile/android/geckoview/intermediates/classes/{}/{}".format(
+            productFlavor,
+            buildType)
+
+set_config('GRADLE_ANDROID_GECKOVIEW_APILINT_FOLDER', gradle_android_intermediates_folder)
+
+@depends(gradle_android_build_config)
 def gradle_android_variant_name(build_config):
     '''Like "withoutGeckoBinariesDebug".'''
     def uncapitalize(s):
         if s:
             return s[0].lower() + s[1:]
         else:
             return s
 
@@ -195,16 +221,25 @@ set_config('GRADLE_ANDROID_TEST_CCOV_REP
 def gradle_android_lint_tasks(build_config):
     '''Gradle tasks run by |mach android lint|.'''
     return [
         'app:lint{app.variant.name}'.format(app=build_config.app),
     ]
 
 set_config('GRADLE_ANDROID_LINT_TASKS', gradle_android_lint_tasks)
 
+@depends(gradle_android_build_config)
+def gradle_android_api_lint_tasks(build_config):
+    '''Gradle tasks run by |mach android api-lint|.'''
+    return [
+        'geckoview:apiLint{geckoview.variant.name}'.format(geckoview=build_config.geckoview),
+    ]
+
+set_config('GRADLE_ANDROID_API_LINT_TASKS', gradle_android_api_lint_tasks)
+
 
 @dependable
 def gradle_android_checkstyle_tasks():
     '''Gradle tasks run by |mach android checkstyle|.'''
     return [
         'app:checkstyle',
     ]
 
@@ -268,16 +303,17 @@ def gradle_android_install_geckoview_exa
         'geckoview_example:install{geckoview_example.variant.name}AndroidTest'.format(geckoview_example=build_config.geckoview_example),
     ]
 
 set_config('GRADLE_ANDROID_INSTALL_GECKOVIEW_EXAMPLE_TASKS', gradle_android_install_geckoview_example_tasks)
 
 
 @depends(
     gradle_android_app_tasks,
+    gradle_android_api_lint_tasks,
     gradle_android_test_tasks,
     gradle_android_lint_tasks,
     gradle_android_checkstyle_tasks,
     gradle_android_findbugs_tasks,
     gradle_android_archive_geckoview_tasks,
     gradle_android_generate_sdk_bindings_tasks,
     gradle_android_generate_generated_jni_wrappers_tasks,
     gradle_android_generate_fennec_jni_wrappers_tasks,
--- a/mobile/android/mach_commands.py
+++ b/mobile/android/mach_commands.py
@@ -5,16 +5,17 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import argparse
 import logging
 import os
 import shutil
 import subprocess
 import zipfile
+import json
 
 from zipfile import ZipFile
 
 import mozpack.path as mozpath
 
 from mozfile import TemporaryDirectory
 
 from mozbuild.base import (
@@ -107,16 +108,37 @@ class MachCommands(MachCommandBase):
                 Firefox for Android.""")
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_generate_fennec_jni_wrappers(self, args):
         ret = self.gradle(
             self.substs['GRADLE_ANDROID_GENERATE_FENNEC_JNI_WRAPPERS_TASKS'] + args, verbose=True)
 
         return ret
 
+    @SubCommand('android', 'api-lint',
+                """Runs apilint against GeckoView.""")
+    @CommandArgument('args', nargs=argparse.REMAINDER)
+    def android_api_lint(self, args):
+        ret = self.gradle(self.substs['GRADLE_ANDROID_API_LINT_TASKS'] + args, verbose=True)
+        folder = self.substs['GRADLE_ANDROID_GECKOVIEW_APILINT_FOLDER']
+
+        with open(os.path.join(
+                self.topobjdir,
+                '{}/apilint-result.json'.format(folder))) as f:
+            result = json.load(f)
+
+            print('SUITE-START | android-api-lint')
+            for r in result['compat_failures'] + result['failures']:
+                print ('TEST-UNEXPECTED-FAIL | {} | {}'.format(r['detail'], r['msg']))
+            for r in result['api_changes']:
+                print ('TEST-UNEXPECTED-FAIL | {} | Unexpected api change'.format(r))
+            print('SUITE-END | android-api-lint')
+
+        return ret
+
     @SubCommand('android', 'test',
                 """Run Android local unit tests.
                 See https://developer.mozilla.org/en-US/docs/Mozilla/Android-specific_test_suites#android-test""")  # NOQA: E501
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def android_test(self, args):
         ret = self.gradle(self.substs['GRADLE_ANDROID_TEST_TASKS'] +
                           ["--continue"] + args, verbose=True)
 
--- a/taskcluster/ci/build/android-stuff.yml
+++ b/taskcluster/ci/build/android-stuff.yml
@@ -144,16 +144,63 @@ android-lint/opt:
             - "mobile/android/**/*.svg"
             - "mobile/android/**/*.xml"
             - "mobile/android/**/Makefile.in"
             - "mobile/android/config/**"
             - "mobile/android/gradle.configure"
             - "mobile/android/**/moz.build"
             - "**/*.gradle"
 
+android-api-lint/opt:
+    description: "Android apilint"
+    index:
+        product: mobile
+        job-name: android-api-lint
+    treeherder:
+        platform: android-4-0-armv7-api16/opt
+        kind: build
+        tier: 1
+        symbol: A(apilint)
+    worker-type: aws-provisioner-v1/gecko-{level}-b-android
+    worker:
+        docker-image: {in-tree: android-build}
+        env:
+            GRADLE_USER_HOME: "/builds/worker/workspace/build/src/mobile/android/gradle/dotgradle-offline"
+            PERFHERDER_EXTRA_OPTIONS: android-api-lint
+        artifacts:
+            - name: public/android/geckoview/api.txt
+              path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/intermediates/classes/withGeckoBinaries/debug/api.txt
+              type: file
+            - name: public/android/geckoview/apilint-result.json
+              path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/intermediates/classes/withGeckoBinaries/debug/apilint-result.json
+              type: file
+        max-run-time: 7200
+    run:
+        using: mozharness
+        actions: [get-secrets, build]
+        config:
+            - builds/releng_base_android_64_builds.py
+        script: "mozharness/scripts/fx_desktop_build.py"
+        secrets: true
+        custom-build-variant-cfg: android-api-lint
+        tooltool-downloads: internal
+    toolchains:
+        - android-gradle-dependencies
+        - android-sdk-linux
+        - linux64-node
+    optimization:
+        skip-unless-changed:
+            - "mobile/android/**/*.java"
+            - "mobile/android/**/*.kt"
+            - "mobile/android/**/Makefile.in"
+            - "mobile/android/config/**"
+            - "mobile/android/gradle.configure"
+            - "mobile/android/**/moz.build"
+            - "**/*.gradle"
+
 android-checkstyle/opt:
     description: "Android checkstyle"
     index:
         product: mobile
         job-name: android-checkstyle
     treeherder:
         platform: android-4-0-armv7-api16/opt
         kind: build
new file mode 100644
--- /dev/null
+++ b/testing/mozharness/configs/builds/releng_sub_android_configs/64_api_lint.py
@@ -0,0 +1,14 @@
+config = {
+    'stage_platform': 'android-api-lint',
+    'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-16-frontend/nightly',
+    'multi_locale_config_platform': 'android',
+    # apilint doesn't produce a package. So don't collect package metrics.
+    'disable_package_metrics': True,
+    'postflight_build_mach_commands': [
+        ['android',
+         'api-lint',
+        ],
+    ],
+    'artifact_flag_build_variant_in_try': None, # There's no artifact equivalent.
+    'max_build_output_timeout': 0,
+}
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -383,16 +383,17 @@ class BuildOptionParser(object):
         'x86-fuzzing-debug': 'builds/releng_sub_%s_configs/%s_x86_fuzzing_debug.py',
         'x86_64': 'builds/releng_sub_%s_configs/%s_x86_64.py',
         'x86_64-artifact': 'builds/releng_sub_%s_configs/%s_x86_64_artifact.py',
         'api-16-partner-sample1': 'builds/releng_sub_%s_configs/%s_api_16_partner_sample1.py',
         'aarch64': 'builds/releng_sub_%s_configs/%s_aarch64.py',
         'android-test': 'builds/releng_sub_%s_configs/%s_test.py',
         'android-test-ccov': 'builds/releng_sub_%s_configs/%s_test_ccov.py',
         'android-checkstyle': 'builds/releng_sub_%s_configs/%s_checkstyle.py',
+        'android-api-lint': 'builds/releng_sub_%s_configs/%s_api_lint.py',
         'android-lint': 'builds/releng_sub_%s_configs/%s_lint.py',
         'android-findbugs': 'builds/releng_sub_%s_configs/%s_findbugs.py',
         'android-geckoview-docs': 'builds/releng_sub_%s_configs/%s_geckoview_docs.py',
         'valgrind': 'builds/releng_sub_%s_configs/%s_valgrind.py',
         'artifact': 'builds/releng_sub_%s_configs/%s_artifact.py',
         'debug-artifact': 'builds/releng_sub_%s_configs/%s_debug_artifact.py',
         'tup': 'builds/releng_sub_%s_configs/%s_tup.py',
     }