#!/usr/bin/env bash ############################################################################## ## ## GitHub Upload+Update Script (V2, combined) for DevPlat Samples ## ############################################################################## update=true upload=true deleteTemp=true useAllSamples=true allSamples=() token= ## Generates a random 32 character alphaneumeric string to use as a post script ## for the temporary code folder (folder will be deleted at end) folderPS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1) #utility function to print to stderr echoerr() { echo "$@" 1>&2; } display_usage() { echo -e "\e[90mUsage: -t | --token [github_auth_token] Input an auth token to access the googlesamples GitHub org (if this is not present, you will be prompted for one later) -s | --samples [sample1 sample2 sample3 ... sampleN] If you don't want to check the entire samples folder, you can specify which samples to use with this option. --upload-only Only uploads new samples - samples with existing repos will be ignored --update-only Only updates samples with existing repos - new samples will be ignored --keep-temp-files Will not delete the temporary directory used to pull/push to Github. (normally deleted upon exit) Preserves logs. This script can be run with no options - it will check the entire ./prebuilts/gradle folder and prompt for an auth token when needed.\e[0m\n" } ############################################################################## ## Make sure we delete the temporary folder (if it gets created) before exiting finish() { if $deleteTemp; then if [ -d "../github-temp$folderPS" ]; then cd .. rm -rf ./github-temp$folderPS elif [ -d "github-temp$folderPS" ]; then rm -rf ./github-temp$folderPS fi fi } # this ensures finish() will always be called no matter how the script ends trap finish EXIT ############################################################################## ## Process input parameters. (see above for usage) ## How this works: ## $# is the number of parameters passed in ## $1 is the first parameter, $2 the second, and so on. (space delimited) ## shift basically left shifts the params array - $1 goes away, $2 becomes $1, etc ## Thus, this while loop iterates through all command line parameters while [[ $# > 0 ]]; do case "$1" in -t|--token) if [[ $2 != -* ]] && [[ $2 ]]; then token="$2"; shift else echoerr -e "Option $1 requires an argument. Cancelling script.\nUse --help to display usage." exit 1 fi;; --update-only) upload=false;; --upload-only) update=false;; --keep-temp-files) deleteTemp=false;; -s|--samples) useAllSamples=false while [[ $2 != -* ]] && [[ $2 ]]; do #if true; then ##for testing if [ -d "./prebuilts/gradle/$2" ]; then allSamples+=("$2") shift else echoerr -e "Sample \"$2\" does not exist in ./prebuilts/gradle. Cancelling script.\n" exit 1 fi done;; -h|--help) display_usage exit 1;; *) echoerr -e "Unknown Option: $1\nUse --help to display usage." exit 1;; esac shift done #ends options while loop if ! $upload && ! $update; then echoerr -e "Do not use both --update-only and --upload-only, no samples will be processed. If you want to do both updates and uploads, no flags are needed. Use --help to display usage." exit 1 fi ############################################################################## ## Get all folders in prebuilts and stick 'em in an array if $useAllSamples; then allSamples=($(ls ./prebuilts/gradle)) fi # [@] returns all items in an array, ${#...} counts them numSamples=${#allSamples[@]} echo "Running script for $numSamples samples" ############################################################################## ## Iterate through all the samples and see if there's ## a repo for them on GitHub already - save results so we only do it once toUpdate=() toUpload=() problemSamples=() curSample=0 echo -ne "Checking for existence of repos... ($curSample/$numSamples)\r" for i in ${allSamples[@]}; do #echo "$i" URL=https://github.com/googlesamples/android-$i result=$(curl -o /dev/null --silent --head --write-out '%{http_code}' "$URL") #echo "$result $URL" if [ "$result" -eq "404" ]; then toUpload+=("$i") elif [ "$result" -eq "200" ]; then toUpdate+=("$i") else problemSamples+=("$i") fi curSample=$(($curSample+1)) echo -ne "Checking for existence of repos... ($curSample/$numSamples)\r" done #close for loop for existence check echo "" ############################################################################## ## For every sample that has a repo already, clone it and diff it against ## the sample code in our git to see if it needs updating. if $update; then needsUpdate=() curSample=0 numUpdates=${#toUpdate[@]} ##make temporary dir to pull code into - will be deleted upon exit. mkdir github-temp$folderPS cd github-temp$folderPS echo -ne "Checking for out-of-date repos... ($curSample/$numUpdates)\r" for i in ${toUpdate[@]}; do URL=https://github.com/googlesamples/android-$i git clone $URL.git &> /dev/null if [ -d "android-$i" ]; then diffResult=$(diff -r --exclude '*.git' ../prebuilts/gradle/$i/ ./android-$i/) #for testing (will show diff in every repo) #diffResult=$(diff -r ../prebuilts/gradle/$i/ ./android-$i/)` #echo $diffResult if [ -n "$diffResult" ]; then needsUpdate+=("$i") fi else echoerr "Something went wrong when cloning $i - result directory does not exist. Leaving temp files in place for further examination." deleteTemp=false; fi curSample=$(($curSample+1)) echo -ne "Checking for out-of-date repos... ($curSample/$numUpdates)\r" done #end of for loop when checking which repos actually need updating echo "" fi echo "" ############################################################################## ## Display the detected changes to be made and get user confirmation if $upload; then if [ ${#toUpload[@]} -ne 0 ]; then echo -e "\n\e[1mNew samples that will be uploaded:\e[0m" for i in ${toUpload[@]}; do echo -e "\e[32m$i\e[0m" done else upload=false echo "Nothing new to upload." fi else echo "No uploads - check skipped on user request" fi if $update; then if [ ${#needsUpdate[@]} -ne 0 ]; then echo -e "\n\e[1mSamples that will be updated:\e[0m" for i in ${needsUpdate[@]}; do echo -e "\e[34m$i\e[0m" done else update=false echo "Nothing to update." fi else echo "No updates - check skipped on user request" fi if [ ${#problemSamples[@]} -ne 0 ]; then echoerr " These repos returned something other than a 404 or 200 result code:" for i in ${problemSamples[@]}; do echoerr "$i" done fi if ! $upload && ! $update; then echo -e "\e[1mLooks like everything's up-to-date.\e[0m\n" else read -p " Do you want to continue? [y/n]: " -n 1 -r echo # if they type anything but an upper or lower case y, don't proceed. if [[ $REPLY =~ ^[Yy]$ ]] then #echo "Commencing Github updates" ############################################################################## ## If the user hasn't supplied a token via parameter, ask now if ! [ -n "$token" ] then read -p " Input a valid googlesamples GitHub access token to continue: " -r token=$REPLY fi ############################################################################## ## Test that token tokenTest=$(curl -o /dev/null --silent \ -H "Authorization: token $token" \ --write-out '%{http_code}' "https://api.github.com/orgs/googlesamples/repos") if [ "$tokenTest" -eq "200" ]; then ############################################################################## ## If there's something to update, do the updates if [ ${#needsUpdate[@]} -ne 0 ] && $update; then for i in ${needsUpdate[@]}; do echo -e "\nUpdating $i" if [ -d "android-$i" ]; then rsync -az --delete --exclude '*.git' ../prebuilts/gradle/$i/ ./android-$i/ cd ./android-$i/ git config user.name "google-automerger" git config user.email automerger@google.com git add . git status git commit -m "Auto-update" git remote set-url origin "https://$token@github.com/googlesamples/android-$i.git" git push origin master #overwrite remote url to not contain auth token git remote set-url origin "http://github.com/googlesamples/android-$i.git" cd .. else echoerr "Something went wrong when cloning $i - result directory does not exist. Leaving temp files in place for further examination." deleteTemp=false; fi done fi #moves out of the temp folder, if we're in it. if [ -d "../github-temp$folderPS" ]; then cd .. fi ############################################################################## ## If there's something new to upload, do the uploads if [ ${#toUpload[@]} -ne 0 ] && $upload; then for i in ${toUpload[@]}; do echo -e "\nUploading $i" repoName="googlesamples/android-$i" CREATE="curl -H 'Authorization: token '$TOKEN \ -d '{\"name\":\"android-'$i'\", \"team_id\":889859}' \ https://api.github.com/orgs/googlesamples/repos" eval $CREATE #add secondary team permissions (robots) ADDTEAM="curl -X PUT \ -H 'Authorization: token '$TOKEN \ -H 'Content-Length: 0' \ https://api.github.com/teams/889856/repos/$repoName" eval $ADDTEAM URL="https://$token@github.com/$repoName" cd $i git init #overrides .gitconfig just for this project - does not alter your global settings. git config user.name "google-automerger" git config user.email automerger@google.com git add . git commit -m "Initial Commit" git remote add origin $URL git push origin master cd .. done fi else echoerr "That token doesn't work. A test returned the code: $tokenTest" fi else echo "User cancelled Github update." fi fi #end of "is there something to do?" if statement