#!/bin/bash # Build iOS codelabs. # # If --verbose (-v) is specified, print the progress of each build. # # If xcpretty is installed (https://github.com/supermarin/xcpretty) then it will # be used in verbose mode. # # Other options can be found by using -h. readonly SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly ROOT_DIR="$SCRIPTS_DIR/.." readonly CURRENT_DIR="$PWD" # Given a path to an Xcode log file in $1, exit with status 0 if it looks like # the failure is expected and can be ignored, or exit with non-zero status # otherwise. function is_expected_failure() { # A test target was specified with the 'build' command. grep --quiet "is not configured for Running" "$1" } # Test if the xcpretty command is available. # # Returns exit status zero if available and non-zero if not. function is_xcpretty_available() { xcpretty > /dev/null 2>&1 # Exit code 127 is the standard "command not found" exit code. if [ $? -eq 127 ]; then return 1 else return 0 fi } # Check that flags have arguments. # # Exits if the flag does not have an argument. function check_arguments() { if [ -z $1 ]; then echo "Argument must be provided to flag." echo "$(basename $0) -h for help" exit 1 fi } # Checks that the argument is a valid reference. # # Exits if the reference is not valid. function check_reference() { reference=$(git ls-remote https://github.com/material-components/material-components-ios.git $1 | wc -l) if [ $reference -eq 0 ]; then echo "Unable to find $1 on GitHub." echo "$(basename $0) -h for help" exit 1 fi } # Checks that the argument is a valid commit. # # Exits if the commit is not valid. function check_commit() { if [ ! $(git cat-file commit $1) ]; then echo "Invalid commit SHA." echo "$(basename $0) -h for help" exit 1 fi } # Parse command-line arguments. # # Note that we're following the command-line exit status convention of zero # to mean "success." verbose=1 all_codelabs=0 has_source=0 # Set default branch to this branch export DEFAULT_BRANCH=$(git symbolic-ref --short HEAD) while [ $# -gt 0 ]; do case $1 in -v|--verbose) verbose=0 shift ;; -rb|--remote-branch) shift check_arguments $1 check_reference $1 if [ $has_source -eq 1 ]; then echo "Only one of --remote-branch/--commit/--tag allowed." echo "$(basename $0) -h for help" exit -1 fi export TEST_BRANCH=$1 has_source=1 shift ;; -c|--commit) shift check_arguments $1 check_commit $1 if [ $has_source -eq 1 ];then echo "Only one of --remote-branch/--commit/--tag allowed." echo "$(basename $0) -h for help" exit -1 fi export TEST_COMMIT=$1 has_source=1 shift ;; -t|--tag) shift check_arguments $1 check_reference $1 if [ $has_source -eq 1 ];then echo "Only one of --remote-branch/--commit/--tag allowed." echo "$(basename $0) -h for help" exit -1 fi export TEST_TAG=$1 has_source=1 shift ;; -a|--all) all_codelabs=1 shift ;; -h|--help) echo echo "Builds MDC iOS Codelabs." echo echo "By default the codelabs are tested against the remote branch tracking your current branch." echo "Your current branch is: $DEFAULT_BRANCH" echo echo "By default the Swift and Objective-C Google I/O 2018 Codelab 104 and Codelab 111 targets will be built." echo "You can build all codelabs by specifying --all." echo echo "Options:" echo "-v, --verbose Verbose logging." echo "-rb, --remote-branch Remote branch of MDC-iOS with which to test codelabs." echo "-c, --commit Commit SHA of MDC-iOS with which to test codelabs." echo "-t, --tag Tag of MDC-iOS with which to test codelabs." echo "-a, --all Build all the codelabs." echo "-h, --help Print this usage information." echo echo "Note: Only one of --remote-branch/--commit/--tag is allowed." echo exit 0 ;; *) echo "Unknown option $1, aborting." exit -1 ;; esac done # Ensure the current branch is a valid remote branch if [ $has_source -eq 0 ]; then check_reference $DEFAULT_BRANCH fi readonly SIGNING_OPTIONS="CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO" # Check for xcpretty once and cache the result. is_xcpretty_available readonly IS_XCPRETTY_AVAILABLE=$? all_builds_ok=1 cd $SCRIPTS_DIR/external # Remove the codelabs folder if it exists already so it can be re-cloned. if [ -d "material-components-ios-codelabs" ]; then rm -rf material-components-ios-codelabs fi git clone https://github.com/material-components/material-components-ios-codelabs.git cd material-components-ios-codelabs # Build only 104 and 111 complete by default. With -a flag, build all. if [ "$all_codelabs" -eq 1 ]; then readonly WORKSPACE_PATHS=$(find $SCRIPTS_DIR/external/material-components-ios-codelabs -name "*.xcworkspace" ! -name "project.xcworkspace") else readonly WORKSPACE_PATHS=$(find $SCRIPTS_DIR/external/material-components-ios-codelabs/MDC-104/*/Complete $SCRIPTS_DIR/external/material-components-ios-codelabs/MDC-111/*/Complete -name "*.xcworkspace" ! -name "project.xcworkspace") fi for workspace_path in $WORKSPACE_PATHS; do # Give the output some meaning, since all the filenames (mostly) the same. workspace=$(basename "$workspace_path") scheme=$(echo "$workspace" | cut -d '.' -f1) codelab=$(echo "$workspace_path" | cut -d/ -f10) language=$(echo "$workspace_path" | cut -d/ -f11) codelab_state=$(echo "$workspace_path" | cut -d/ -f12) log_file=$(dirname "$workspace_path")/"build_log_for_scheme_${scheme}.txt" options="-workspace $workspace_path -scheme $scheme $SIGNING_OPTIONS" build_command="xcodebuild $options build" pod_install="pod install --project-directory=$(dirname "$workspace_path")" # pod install so the specified branch/commit/tag can be used if [ -f $(dirname "$workspace_path")/Podfile ]; then if [ "$verbose" -eq 0 ]; then $pod_install else $pod_install --silent fi else echo "No Podfile available." exit 1 fi echo "xcodebuild $scheme in $workspace for $codelab $codelab_state in $language." if [ "$verbose" -eq 0 ]; then if [ "$IS_XCPRETTY_AVAILABLE" -eq 0 ]; then $build_command 2>&1 | tee "$log_file" | xcpretty else $build_command 2>&1 | tee "$log_file" fi else $build_command >"$log_file" 2>&1 fi # We need to have the output in a log file in all cases so we can check for # expected failures. if [ ${PIPESTATUS[0]} -eq 0 ] || is_expected_failure "$log_file"; then rm "$log_file" else all_builds_ok=0 echo echo "Failed to build $scheme in $workspace:" echo "Log left in $log_file." echo "Continuing with next build..." echo fi done cd $CURRENT_DIR # If any build failed, exit with a failure exit status so continuous integration # tools can react appropriately. if [ "$all_builds_ok" -eq 1 ]; then exit 0 else exit 1 fi