diff --git a/app-deploy.sh b/app-deploy.sh index 47d899c..c56dc36 100755 --- a/app-deploy.sh +++ b/app-deploy.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash source ./.deploy-options.sh +source /usr/local/bin/.app-deploy-sources/__auto_update.sh +source /usr/local/bin/.app-deploy-sources/__init.sh +source /usr/local/bin/.app-deploy-sources/__initial_checkup.sh +source /usr/local/bin/.app-deploy-sources/__base_tag_handling.sh +source /usr/local/bin/.app-deploy-sources/__deploy_tags.sh ############################################################### # DEPLOY SCRIPT # @@ -8,11 +13,9 @@ source ./.deploy-options.sh # Script used for creating the specific # # tag used for triggering the CI deployment # # # -# End tag should look like this: # -# internal-all/v1.0.0-1234 # # # # Prepared by Jasmin Abou Aldan # -# Copyright (c) 2020 Infinum. All rights reserved. # +# Copyright (c) 2024 Infinum. All rights reserved. # ############################################################### # Use global variables at your own risk as this can be overridden in the future. @@ -34,257 +37,26 @@ function main { # BASE INFO # commit, tag, synced head,... - initial_checkup + __initial_checkup # CREATE TAG - deploy_options - input_to_tags - create_app_version_and_build_number + deploy_options # Get from .deploy-options.sh, setup per project + __input_to_tags + + if [ -z "$script_version" ] || [ "$script_version" == "v1" ]; then + __create_app_version_and_build_number + elif [ "$script_version" == "v2" ]; then + __create_trigger_ci_timestamp_tag + fi # CREATE CHANGELOG - generate_tag_and_changelog + __generate_tag_and_changelog # DEPLOY - push_tag_and_start_deploy -} - -################################# -# HELPERS # -################################# - -function initial_checkup { - - echo - echo "###############################################################" - echo "# COMMIT CHECK #" - echo "###############################################################" - echo - - if [ $# -gt 1 ] || [ "$1" == '-h' ] || [ "$1" == '--help' ] || [ "$1" == 'help' ]; then - echo "Usage: $0 [optional-commit-hash]" - exit 1 - fi - - if [ $# -eq 1 ]; then - commit="$1" - else - commit=`git rev-parse --short HEAD` - fi - - commit_message=`git log --format=%B -n 1 ${commit}` - - if [ $? -ne 0 ]; then - echo "Failed to get message for commit '$commit'. Aborting." - exit 2 - fi - - echo "---------------------------------------------------------------" - echo "Targeting commit: ${bold}$commit${normal}" - echo "---------------------------------------------------------------" - echo "$commit_message" - echo "---------------------------------------------------------------" - - remote_branches=`git branch -r --contains ${commit}` - if [ $? -ne 0 ] || [ -z "$remote_branches" ]; then - echo - echo "Commit '$commit' not found on any remote branch." - if $enable_automatic_commit_push ; then - current_branch=`git rev-parse --abbrev-ref HEAD` - echo "Pushing..." - git push origin "$current_branch" - else - read -r -p "Do you want to push it? [y/n] " push_to_git - if [[ ${push_to_git} =~ ^(yes|y|Y) ]] || [ -z ${push_to_git} ]; then - current_branch=`git rev-parse --abbrev-ref HEAD` - echo "Pushing..." - git push origin "$current_branch" - else - echo "Aborting." - exit 3 - fi - fi - fi -} - -function input_to_tags { - - # Parse all selected options - IFS=', ' read -r -a environments_array <<< "$target_selection" - - environments_to_build=() - - for environment in "${environments_array[@]}"; do - if [ ${environment} -le $((${#environments[@]} - 1)) -a ${environment} -ge 0 ]; then - environments_to_build+=("${environments[${environment}]}") - else - echo "Error: You chose wrong, young Jedi. This is the end of your path..." - exit 4 - fi - done -} - -function create_app_version_and_build_number { - - echo - echo "###############################################################" - echo "# APP VERSION #" - echo "###############################################################" - echo - - # App version number - last_known_tag=`git describe --abbrev=0 --tags | sed -E 's/.*v([0-9]*\.?[0-9]*\.?[0-9]*)(-.*)?/\1/'` - - if [ -z "$last_known_tag" ] - then - read -r -p "Enter current app version (e.g. 1.0.0): " appversion - else - read -r -p "Press enter to use last known version: ${bold}$last_known_tag${normal}. (or enter different version) " new_version - [ -z "$new_version" ] && appversion=$last_known_tag || appversion=$new_version - fi - - if ! [[ "$appversion" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] - then - echo "App version is in wrong format (use M.m.p format, e.g. 1.0.0). Aborting..." - exit 5 - fi - - # Build number - - echo "Getting next build number..." - - tags_count=`git ls-remote --t --refs -q | grep -o -E '[[:<:]]\d+(\n|$)' | sort -nr | head -n1` - - if [ -z "$tags_count" ]; then - tags_count=0 - else - tags_count=$((tags_count+1)) - fi - - # Create tag name internal{-TargetX}/vM.m.p-{number of commits}. E.g. internal-all/v1.0.0-1234 - tags_to_deploy=() - for target in "${environments_to_build[@]}"; do - tags_to_deploy+=("$target/v$appversion-$tags_count") - done - - echo - echo "Next app version is: ${bold}v$appversion-$tags_count${normal}" - sleep 1 -} - -function generate_tag_and_changelog { - - echo - echo "###############################################################" - echo "# CHANGELOG #" - echo "###############################################################" - echo - echo "------------------------------------------------------------" - echo "Enter changelog message..." - echo "------------------------------------------------------------" - sleep 1 - - tag_message_added=0 - for tag in "${tags_to_deploy[@]}"; do - - if [ ${tag_message_added} -eq 1 ]; then - TAG=`git describe --exact-match` - CHANGELOG=`git show -s --format=%N ${TAG} | tail -n +4` - git tag -a "$tag" -m "${CHANGELOG}" - else - git tag -a "$tag" - tag_message_added=1 - fi - done -} - -function push_tag_and_start_deploy { - - changelog_message=`git show -s --format=%N ${tag} | tail -n +4` - - if ! $enable_final_confirmation ; then - push_tag - fi - - echo - echo "###############################################################" - echo "# DEPLOY #" - echo "###############################################################" - echo - echo "---------------------------------------------------------------" - echo " ~ CONFIGURATION ~ " - echo - echo "Version: ${bold}v$appversion-$tags_count${normal}" - for tag in "${tags_to_deploy[@]}"; do - echo "Tag: ${bold}$tag${normal}" - done - echo - echo "Changelog:" - echo "${bold}$changelog_message${normal}" - echo "---------------------------------------------------------------" - echo - read -r -p "Is configuration correct for the CI deployment? [y or enter / n] " response - echo - - if [[ ${response} =~ ^(no|n|N) ]]; then - echo "Aborting." - for tag in "${tags_to_deploy[@]}"; do - git tag -d "$tag" - done - exit 6 - fi - - push_tag -} - -function push_tag { - # Push if everything is ok! - if [ $? -eq 0 ]; then - echo - echo "------------------------------------------------------------" - echo - for tag in "${tags_to_deploy[@]}"; do - # Push if everything is ok! - echo "Tag ${bold}${tag}${normal} added. Pushing tag ..." - git push origin "$tag" - done - echo - echo "============================================================" - echo "DEPLOY TAG SUCCESSFULLY ADDED!" - echo "CHECK YOUR CI FOR THE BUILD STATUS" - echo "============================================================" - echo - exit 0 - else - echo - echo "------------------------------------------------------------" - echo "Failed to add tag. Aborting." - echo "------------------------------------------------------------" - exit 7 - fi -} - -################################# -# UPDATE # -################################# - -function script_auto_update { - echo - echo "Please wait until main script is finished with updating..." - echo - echo "Fetching new data..." - if [ ! -d ".app_deploy_tmp" ]; then - mkdir .app_deploy_tmp - fi - git clone --quiet https://github.com/infinum/app-deploy-script.git .app_deploy_tmp - echo "Updating..." - cat .app_deploy_tmp/app-deploy.sh > /usr/local/bin/app-deploy - echo "Cleaning temporary files..." - rm -rf .app_deploy_tmp - echo "Updating finished!" - exit 0 + __push_tag_and_start_deploy } ################################# @@ -298,12 +70,19 @@ echo echo "###############################################################" echo "# DEPLOY SCRIPT #" echo "# #" -echo "# Copyright (c) 2020 Infinum. #" +echo "# Copyright (c) 2024 Infinum. #" echo "###############################################################" echo -if ! [ "$1" == '--update' ] ; then +if [ "$1" == '--update' ] ; then + __script_auto_update +elif [ "$1" == 'init' ] ; then + __init +elif [ -z "$1" ] || [ "$1" == 'trigger' ] ; then # Empty input or "trigger" main -else - script_auto_update +else + echo + echo "Unsuported command!" + echo + exit 0 fi diff --git a/install.sh b/install.sh index 4908a4c..5960b81 100755 --- a/install.sh +++ b/install.sh @@ -25,16 +25,32 @@ if ! [[ ${c} =~ ^(yes|y|Y) ]] || [ -z ${c} ]; then fi echo echo "Fetching script data..." -mkdir .app_deploy_tmp -git clone --quiet https://github.com/infinum/app-deploy-script.git .app_deploy_tmp + +# Create temp folder +if [ ! -d ".app_deploy_tmp" ]; then + mkdir .app_deploy_tmp +else + rm -rf .app_deploy_tmp +fi + +# Get install files +git clone --quiet https://github.com/infinum/app-deploy-script.git --branch feature/v2/local-trigger .app_deploy_tmp echo "Installing..." + +# Move main script to bin folder cat .app_deploy_tmp/app-deploy.sh > /usr/local/bin/app-deploy -if ! [ -f ./.deploy-options.sh ]; then - cat .app_deploy_tmp/deploy-options.sh > ./.deploy-options.sh +# Move helpers to helpers folder inside bin +if [ ! -d "/usr/local/bin/.app-deploy-sources" ]; then + mkdir /usr/local/bin/.app-deploy-sources/ fi +cp -a .app_deploy_tmp/sources/. /usr/local/bin/.app-deploy-sources/ +# Add permission to read files chmod +rx /usr/local/bin/app-deploy +chmod +rx /usr/local/bin/.app-deploy-sources/ + +# Remove temp install folder rm -rf .app_deploy_tmp echo "Done!" diff --git a/sources/__auto_update.sh b/sources/__auto_update.sh new file mode 100644 index 0000000..aa092e2 --- /dev/null +++ b/sources/__auto_update.sh @@ -0,0 +1,36 @@ +################################# +# UPDATE # +################################# + +function __script_auto_update { + echo + echo "Please wait until main script is finished with updating..." + echo + echo "Fetching new data..." + + # Create temp folder + # if [ ! -d ".app_deploy_tmp" ]; then + # mkdir .app_deploy_tmp + # else + # rm -rf .app_deploy_tmp + # fi + + # Get new data + # git clone --quiet https://github.com/infinum/app-deploy-script.git --branch feature/v2/local-trigger .app_deploy_tmp + # echo "Updating..." + + # # Move new data to bin / helpers + # cat .app_deploy_tmp/app-deploy.sh > /usr/local/bin/app-deploy + # cp -a .app_deploy_tmp/sources/. /usr/local/bin/.app-deploy-sources/ + + # LOCAL DEVELOPMENT + # Comment when not in use + cat /Users/jaco/Infinum/Infinum_projects/AppDeployScript/app-deploy-script/app-deploy.sh > /usr/local/bin/app-deploy + cp -a /Users/jaco/Infinum/Infinum_projects/AppDeployScript/app-deploy-script/sources/. /usr/local/bin/.app-deploy-sources/ + + # Remove temp folder + # rm -rf .app_deploy_tmp + + echo "Updating finished!" + exit 0 +} diff --git a/sources/__base_tag_handling.sh b/sources/__base_tag_handling.sh new file mode 100644 index 0000000..a87cfbb --- /dev/null +++ b/sources/__base_tag_handling.sh @@ -0,0 +1,119 @@ +################################# +# CREATE TAG # +################################# + +# Parse all selected options +function __input_to_tags { + + IFS=', ' read -r -a environments_array <<< "$target_selection" + + environments_to_build=() + + for environment in "${environments_array[@]}"; do + if [ ${environment} -le $((${#environments[@]} - 1)) -a ${environment} -ge 0 ]; then + environments_to_build+=("${environments[${environment}]}") + else + echo "Error: You chose wrong, young Jedi. This is the end of your path..." + exit 4 + fi + done +} + +# Generate app version and build number +# Used in v1 version of the script +function __create_app_version_and_build_number { + + echo + echo "###############################################################" + echo "# APP VERSION #" + echo "###############################################################" + echo + + # App version number + last_known_tag=`git describe --abbrev=0 --tags | sed -E 's/.*v([0-9]*\.?[0-9]*\.?[0-9]*)(-.*)?/\1/'` + + if [ -z "$last_known_tag" ] + then + read -r -p "Enter current app version (e.g. 1.0.0): " appversion + else + read -r -p "Press enter to use last known version: ${bold}$last_known_tag${normal}. (or enter different version) " new_version + [ -z "$new_version" ] && appversion=$last_known_tag || appversion=$new_version + fi + + if ! [[ "$appversion" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] + then + echo "App version is in wrong format (use M.m.p format, e.g. 1.0.0). Aborting..." + exit 5 + fi + + # Build number + + echo "Getting next build number..." + + tags_count=`git ls-remote --t --refs -q | grep -o -E '[[:<:]]\d+(\n|$)' | sort -nr | head -n1` + + if [ -z "$tags_count" ]; then + tags_count=0 + else + tags_count=$((tags_count+1)) + fi + + # Create tag name internal{-TargetX}/vM.m.p-{number of commits}. E.g. internal-all/v1.0.0-1234 + tags_to_deploy=() + for target in "${environments_to_build[@]}"; do + tags_to_deploy+=("$target/v$appversion-$tags_count") + done + + echo + echo "Next app version is: ${bold}v$appversion-$tags_count${normal}" + sleep 1 +} + +# Generate trigger tag with timestamp +# Used in v2 version of the script +function __create_trigger_ci_timestamp_tag { + + # Create tag name ci/{environment}/{timestamp}}. E.g. ci/internal-staging/2024-12-05T17-16-28 + tags_to_deploy=() + + # Prefix ci + trigger_tag="ci/" + + # Environments + for target in "${environments_to_build[@]}"; do + trigger_tag+="$target/" + done + + # Sufix timestamp + trigger_tag+="$(date +%Y-%m-%dT%H-%M-%S)" + + # Assign to shared property + tags_to_deploy=("$trigger_tag") +} + +# Changelog +function __generate_tag_and_changelog { + + echo + echo "###############################################################" + echo "# CHANGELOG #" + echo "###############################################################" + echo + echo "------------------------------------------------------------" + echo "Enter changelog message..." + echo "------------------------------------------------------------" + sleep 1 + + tag_message_added=0 + for tag in "${tags_to_deploy[@]}"; do + + if [ ${tag_message_added} -eq 1 ]; then + TAG=`git describe --exact-match` + CHANGELOG=`git show -s --format=%N ${TAG} | tail -n +4` + git tag -a "$tag" -m "${CHANGELOG}" + else + git tag -a "$tag" + tag_message_added=1 + fi + done +} \ No newline at end of file diff --git a/sources/__deploy_tags.sh b/sources/__deploy_tags.sh new file mode 100644 index 0000000..3abfb75 --- /dev/null +++ b/sources/__deploy_tags.sh @@ -0,0 +1,71 @@ +################################# +# DEPLOY # +################################# + +function __push_tag_and_start_deploy { + + changelog_message=`git show -s --format=%N ${tag} | tail -n +4` + + if ! $enable_final_confirmation ; then + __push_tag + fi + + echo + echo "###############################################################" + echo "# DEPLOY #" + echo "###############################################################" + echo + echo "---------------------------------------------------------------" + echo " ~ CONFIGURATION ~ " + echo + if [ -n "$appversion" ]; then + echo "Version: ${bold}v$appversion-$tags_count${normal}" + fi + for tag in "${tags_to_deploy[@]}"; do + echo "Tag: ${bold}$tag${normal}" + done + echo + echo "Changelog:" + echo "${bold}$changelog_message${normal}" + echo "---------------------------------------------------------------" + echo + read -r -p "Is configuration correct for the CI deployment? [y or enter / n] " response + echo + + if [[ ${response} =~ ^(no|n|N) ]]; then + echo "Aborting." + for tag in "${tags_to_deploy[@]}"; do + git tag -d "$tag" + done + exit 6 + fi + + __push_tag +} + +function __push_tag { + # Push if everything is ok! + if [ $? -eq 0 ]; then + echo + echo "------------------------------------------------------------" + echo + for tag in "${tags_to_deploy[@]}"; do + # Push if everything is ok! + echo "Tag ${bold}${tag}${normal} added. Pushing tag ..." + git push origin "$tag" + done + echo + echo "============================================================" + echo "DEPLOY TAG SUCCESSFULLY ADDED!" + echo "CHECK YOUR CI FOR THE BUILD STATUS" + echo "============================================================" + echo + exit 0 + else + echo + echo "------------------------------------------------------------" + echo "Failed to add tag. Aborting." + echo "------------------------------------------------------------" + exit 7 + fi +} \ No newline at end of file diff --git a/sources/__init.sh b/sources/__init.sh new file mode 100644 index 0000000..b7b8d0c --- /dev/null +++ b/sources/__init.sh @@ -0,0 +1,21 @@ +################################# +# INIT NEW PROJECT # +################################# + +function __init { + + if [ -e "./.deploy-options.sh" ]; then + echo "Options file already exists." + echo "If you continue, stored options will be overriden!" + echo + read -r -p "Do you want to proceed? [y/n] " c + if ! [[ ${c} =~ ^(yes|y|Y) ]] || [ -z ${c} ]; then + exit 1 + fi + fi + + cat /usr/local/bin/.app-deploy-sources/deploy-options.sh > ./.deploy-options.sh + echo "The options file was generated successfully!" + echo "NOTE: Change default values to the project specific." + echo +} \ No newline at end of file diff --git a/sources/__initial_checkup.sh b/sources/__initial_checkup.sh new file mode 100644 index 0000000..8ebba91 --- /dev/null +++ b/sources/__initial_checkup.sh @@ -0,0 +1,59 @@ +################################# +# INITIAL CHECK # +################################# + +# Check commit, tag, synced head,... +# Report any uncommited changes, unpushed commits, etc.. +function __initial_checkup { + + echo + echo "###############################################################" + echo "# COMMIT CHECK #" + echo "###############################################################" + echo + + if [ $# -gt 1 ] || [ "$1" == '-h' ] || [ "$1" == '--help' ] || [ "$1" == 'help' ]; then + echo "Usage: $0 [optional-commit-hash]" + exit 1 + fi + + if [ $# -eq 1 ]; then + commit="$1" + else + commit=`git rev-parse --short HEAD` + fi + + commit_message=`git log --format=%B -n 1 ${commit}` + + if [ $? -ne 0 ]; then + echo "Failed to get message for commit '$commit'. Aborting." + exit 2 + fi + + echo "---------------------------------------------------------------" + echo "Targeting commit: ${bold}$commit${normal}" + echo "---------------------------------------------------------------" + echo "$commit_message" + echo "---------------------------------------------------------------" + + remote_branches=`git branch -r --contains ${commit}` + if [ $? -ne 0 ] || [ -z "$remote_branches" ]; then + echo + echo "Commit '$commit' not found on any remote branch." + if $enable_automatic_commit_push ; then + current_branch=`git rev-parse --abbrev-ref HEAD` + echo "Pushing..." + git push origin "$current_branch" + else + read -r -p "Do you want to push it? [y/n] " push_to_git + if [[ ${push_to_git} =~ ^(yes|y|Y) ]] || [ -z ${push_to_git} ]; then + current_branch=`git rev-parse --abbrev-ref HEAD` + echo "Pushing..." + git push origin "$current_branch" + else + echo "Aborting." + exit 3 + fi + fi + fi +} \ No newline at end of file diff --git a/deploy-options.sh b/sources/deploy-options.sh similarity index 66% rename from deploy-options.sh rename to sources/deploy-options.sh index d5157b7..c2fcd9c 100644 --- a/deploy-options.sh +++ b/sources/deploy-options.sh @@ -1,5 +1,19 @@ #!/usr/bin/env bash +# Defines the version of workflow supported by this script. Currently, two versions are available, v1 and v2. +# +# v1 # +# An old workflow where the local script will ask you for the app version. +# The script will generate the next build number that can be used on the CI/CD. +# Each selected environment will get its tag, e.g., for Staging and UAT, you'll get two tags internal-staging/v1.0.0-1 and internal-uat/v1.0.0-1 +# +# v2 # +# New workflow, where the local script is used only as a CI/CD trigger. +# The script will not generate a build number or ask you for the app version. +# Each selected environment is concatenated into one tag. The tag will always start with `ci/` and end with `/{timestamp}.` E.g., ci/internal-staging/internal-uat/{timestamp} +# +# By default, this option is set to new workflow - v2 +script_version=v2 # If enabled, console will be cleared on every script run. # By default, this option is enabled use_automatic_console_clean=true @@ -46,15 +60,15 @@ function deploy_options { echo echo "==================" echo - echo "---------------------" - echo "| APP STORE CONNECT |" - echo "---------------------" + echo "---------" + echo "| STORE |" + echo "---------" echo - echo "[3] App Store" + echo "[3] App/Play Store" echo read -r -p "Enter number in square brackets: " target_selection - # Array for creating first part of the tag. + # Array for creating first part of the tag. # Should be in sync with options shown to the user. - environments=("internal-staging" "internal-uat" "internal-production" "appstore") + environments=("internal-staging" "internal-uat" "internal-production" "store") }