Let Travis build the gallery and push to TestFlight / Play Store (#14408)

* iOS works

* Works on Android

* Take in commit number in iOS also. Get rid of image upload for Android. It's just a waste of bandwidth

* Tweak to fix on Travis
diff --git a/.travis.yml b/.travis.yml
index 51dccfd..f3f4c81 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,16 +2,21 @@
 os:
   - linux
   - osx
+osx_image: xcode9.2
 env:
   - SHARD=analyze
   - SHARD=tests
   - SHARD=docs
+  - SHARD=build_and_deploy_gallery
 matrix:
   exclude:
   - os: osx
     env: SHARD=analyze
   - os: osx
     env: SHARD=docs
+  # TODO(xster): remove this when we know it works on Travis.
+  allow_failures:
+  - env: SHARD=build_and_deploy_gallery
 sudo: false
 filter_secrets: false
 
@@ -22,6 +27,7 @@
     sources:
       - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
     packages:
+      - lib32stdc++6
       - libstdc++6
       - fonts-droid
 language: node_js
@@ -31,6 +37,7 @@
   # We rely on git tags for determining the version.
   depth: false
 cache:
+  bundler: true
   directories:
     - $HOME/.pub-cache
 install:
@@ -41,4 +48,4 @@
   - ./dev/bots/travis_setup.sh
 script:
   - ulimit -S -n 2048 # https://github.com/flutter/flutter/issues/2976
-  - (./bin/cache/dart-sdk/bin/dart ./dev/bots/test.dart && ./dev/bots/travis_upload.sh)
+  - ./dev/bots/travis_script.sh
diff --git a/dev/bots/travis_install.sh b/dev/bots/travis_install.sh
index 041ce17..bee490c 100755
--- a/dev/bots/travis_install.sh
+++ b/dev/bots/travis_install.sh
@@ -3,5 +3,6 @@
 
 if [ -n "$TRAVIS" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
   gem install coveralls-lcov
+  gem install bundler
   npm install -g firebase-tools@">=3.6.1 <3.7.0"
 fi
diff --git a/dev/bots/travis_script.sh b/dev/bots/travis_script.sh
new file mode 100755
index 0000000..982d3b1
--- /dev/null
+++ b/dev/bots/travis_script.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -ex
+
+export PATH="$PWD/bin:$PWD/bin/cache/dart-sdk/bin:$PATH"
+
+if [ "$SHARD" = "build_and_deploy_gallery" ]; then
+  echo "Building and deploying Flutter Gallery"
+  if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+    echo "Building Flutter Gallery for Android..."
+    export ANDROID_HOME=`pwd`/android-sdk
+    (cd examples/flutter_gallery; flutter build apk --release)
+    echo "Android Flutter Gallery built"
+    if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then # TODO(xster): add back && [ "$TRAVIS_BRANCH" = "dev" ] after testing
+      echo "Deploying to Play Store..."
+      (cd examples/flutter_gallery/android; bundle exec fastlane deploy_play_store)
+    else
+      echo "Flutter Gallery is only deployed to the Play Store on merged dev branch commits"
+    fi
+  elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
+    echo "Building Flutter Gallery for iOS..."
+    (cd examples/flutter_gallery; flutter build ios --release --no-codesign)
+    echo "iOS Flutter Gallery built"
+    if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then # TODO(xster): add back && [ "$TRAVIS_BRANCH" = "dev" ] after testing
+      echo "Re-building with distribution profile and deploying to TestFlight..."
+      (cd examples/flutter_gallery/ios; bundle exec fastlane build_and_deploy_testflight)
+    else
+      echo "Flutter Gallery is only deployed to the TestFlight on merged dev branch commits"
+    fi
+  fi
+elif [ "$SHARD" = "docs" ]; then
+  if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+    # Generate the API docs, upload them
+    ./dev/bots/docs.sh
+  fi
+else
+  dart ./dev/bots/test.dart
+fi
diff --git a/dev/bots/travis_setup.sh b/dev/bots/travis_setup.sh
index 040cdee..22a70e0 100755
--- a/dev/bots/travis_setup.sh
+++ b/dev/bots/travis_setup.sh
@@ -10,6 +10,34 @@
   echo "Installing Google Cloud SDK..."
   curl https://sdk.cloud.google.com | bash > /dev/null
   echo "Google Cloud SDK installation completed."
+
+  if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$SHARD" = "build_and_deploy_gallery" ]; then
+    # Background for not using Travis's built-in Android tags
+    # https://github.com/flutter/plugins/pull/145
+    # Copied from https://github.com/flutter/plugins/blame/master/.travis.yml
+    wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
+    mkdir android-sdk
+    unzip -qq sdk-tools-linux-3859397.zip -d android-sdk
+    export ANDROID_HOME=`pwd`/android-sdk
+    export PATH=`pwd`/android-sdk/tools/bin:$PATH
+    mkdir -p /home/travis/.android # silence sdkmanager warning
+    echo 'count=0' > /home/travis/.android/repositories.cfg # silence sdkmanager warning
+    # suppressing output of sdkmanager to keep log under 4MB (travis limit)
+    echo y | sdkmanager "tools" >/dev/null
+    echo y | sdkmanager "platform-tools" >/dev/null
+    echo y | sdkmanager "build-tools;26.0.3" >/dev/null
+    echo y | sdkmanager "platforms;android-26" >/dev/null
+    echo y | sdkmanager "extras;android;m2repository" >/dev/null
+    echo y | sdkmanager "extras;google;m2repository" >/dev/null
+    echo y | sdkmanager "patcher;v4" >/dev/null
+    sdkmanager --list
+    wget http://services.gradle.org/distributions/gradle-4.1-bin.zip
+    unzip -qq gradle-4.1-bin.zip
+    export GRADLE_HOME=$PWD/gradle-4.1
+    export PATH=$GRADLE_HOME/bin:$PATH
+    gradle -v
+    ./bin/flutter doctor
+  fi
 fi
 
 # disable analytics on the bots and download Flutter dependencies
diff --git a/dev/bots/travis_upload.sh b/dev/bots/travis_upload.sh
deleted file mode 100755
index f48a245..0000000
--- a/dev/bots/travis_upload.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-export PATH="$PWD/bin:$PWD/bin/cache/dart-sdk/bin:$PATH"
-
-if [ "$TRAVIS_OS_NAME" = "linux" ] && \
-   [ "$SHARD" = "docs" ]; then
-  # generate the API docs, upload them
-  ./dev/bots/docs.sh
-fi
diff --git a/examples/flutter_gallery/android/app/build.gradle b/examples/flutter_gallery/android/app/build.gradle
index 66aa041..a0633f4 100644
--- a/examples/flutter_gallery/android/app/build.gradle
+++ b/examples/flutter_gallery/android/app/build.gradle
@@ -11,6 +11,14 @@
     throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
 }
 
+def flutterVersion = file("$flutterRoot/version").text
+def flutterVersionComponents = flutterVersion.split(/[^0-9]+/)
+// Let the integer version code of xx.yy.zz-pre.nnn be xxyyzznnn.
+int flutterVersionCode = Math.min(flutterVersionComponents[0].toInteger(), 20) * 100000000
+flutterVersionCode += Math.min(flutterVersionComponents[1].toInteger(), 99) * 1000000
+flutterVersionCode += Math.min(flutterVersionComponents[2].toInteger(), 999) * 1000
+flutterVersionCode += Math.min(flutterVersionComponents[3]?.toInteger() ?: 0, 999)
+
 apply plugin: 'com.android.application'
 apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
 
@@ -25,8 +33,9 @@
         applicationId "io.flutter.demo.gallery"
         minSdkVersion 16
         targetSdkVersion 27
-        versionCode 1
-        versionName "0.0.1"
+        // The Gallery app's version is defined by the Flutter framework's version.
+        versionCode flutterVersionCode
+        versionName "$flutterVersion"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
     }
 
diff --git a/examples/flutter_gallery/android/fastlane/Fastfile b/examples/flutter_gallery/android/fastlane/Fastfile
index eb4ced6..cc7a596 100644
--- a/examples/flutter_gallery/android/fastlane/Fastfile
+++ b/examples/flutter_gallery/android/fastlane/Fastfile
@@ -7,13 +7,14 @@
 # flutter build apk --release
 # to build the app using the Flutter toolchain.
 platform :android do
-  desc 'Push the built release APK to alpha'
-  lane :deploy_play_store_alpha do
+  desc 'Push the built release APK to alpha or beta depending on current branch'
+  lane :deploy_play_store do
     upload_to_play_store(
-      track: 'alpha',
+      track: ENV['TRAVIS_BRANCH'] == 'beta' ? 'beta' : 'alpha',
       apk: '../build/app/outputs/apk/release/app-release.apk',
       json_key_data: ENV['GOOGLE_DEVELOPER_SERVICE_ACCOUNT_ACTOR_FASTLANE'],
-      skip_upload_screenshots: true
+      skip_upload_screenshots: true,
+      skip_upload_images: true
     )
   end
 end
diff --git a/examples/flutter_gallery/android/fastlane/metadata/android/en-US/images/icon.png b/examples/flutter_gallery/android/fastlane/metadata/android/en-US/images/icon.png
deleted file mode 100644
index a3c444c..0000000
--- a/examples/flutter_gallery/android/fastlane/metadata/android/en-US/images/icon.png
+++ /dev/null
Binary files differ
diff --git a/examples/flutter_gallery/ios/fastlane/Fastfile b/examples/flutter_gallery/ios/fastlane/Fastfile
index 258866f..68d38c8 100644
--- a/examples/flutter_gallery/ios/fastlane/Fastfile
+++ b/examples/flutter_gallery/ios/fastlane/Fastfile
@@ -10,15 +10,20 @@
 # 1- Signing using the publishing credentials; and
 # 2- xcodebuild with archive option
 platform :ios do
-  desc "Push a new release to TestFlight"
+  desc 'Push a new release to TestFlight'
   lane :build_and_deploy_testflight do
     # Doesn't do anything when not on Travis.
     setup_travis
 
+    increment_version_number(
+      # Relative to this file. Accept only digits and dots.
+      version_number: File.read('../../../../version').gsub(/[^0-9\.]/, '')
+    )
+
     # Retrieves all the necessary certs and provisioning profiles.
     sync_code_signing(
-      git_url: ENV["PUBLISHING_MATCH_CERTIFICATE_REPO"],
-      type: "appstore",
+      git_url: ENV['PUBLISHING_MATCH_CERTIFICATE_REPO'],
+      type: 'appstore',
       readonly: true
     )
 
@@ -27,19 +32,19 @@
     # then run session.
     disable_automatic_code_signing
     update_project_provisioning(
-      xcodeproj: "Runner.xcodeproj",
-      target_filter: "Runner",
-      build_configuration: "Release",
-      profile: ENV["sigh_io.flutter.demo.gallery_appstore_profile-path"],
+      xcodeproj: 'Runner.xcodeproj',
+      target_filter: 'Runner',
+      build_configuration: 'Release',
+      profile: ENV['sigh_io.flutter.demo.gallery_appstore_profile-path'],
     )
 
     # Build and archive the app again.
     build_ios_app(
-      workspace: "Runner.xcworkspace",
-      scheme: "Runner",
-      export_method: "app-store",
+      workspace: 'Runner.xcworkspace',
+      scheme: 'Runner',
+      export_method: 'app-store',
       # Verify that the right signing identity is used for publishing.
-      codesigning_identity: "iPhone Distribution: Store Ladd (S8QB4VV633)",
+      codesigning_identity: 'iPhone Distribution: Store Ladd (S8QB4VV633)',
     )
 
     upload_to_testflight