From c4de7bd274c9cf1e5bd81c68f12fcf926ed7200d Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 08:41:52 +0200 Subject: [PATCH 1/8] feat: add new --version option --- deploy | 4 ++++ src/console_header.sh | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/deploy b/deploy index 20a522a..b7d7c60 100755 --- a/deploy +++ b/deploy @@ -43,6 +43,10 @@ while [[ $# -gt 0 ]]; do console_header::print_help exit 0 ;; + -v|--version) + console_header::print_version + exit 0 + ;; -s|--source) SOURCE_BRANCH="$2" shift diff --git a/src/console_header.sh b/src/console_header.sh index e0a79e8..d76a472 100644 --- a/src/console_header.sh +++ b/src/console_header.sh @@ -1,6 +1,10 @@ #!/bin/bash set -o allexport +function console_header::print_version() { + printf "%s\n" "$DEPLOY_VERSION" +} + function console_header::print_help() { cat < Date: Wed, 18 Sep 2024 08:47:48 +0200 Subject: [PATCH 2/8] refactor: move version inside src/version.txt --- .github/RELEASE.md | 2 +- deploy | 3 --- src/console_header.sh | 2 +- src/main.sh | 1 - src/version.txt | 1 + 5 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 src/version.txt diff --git a/.github/RELEASE.md b/.github/RELEASE.md index 09207e0..5ba0a86 100644 --- a/.github/RELEASE.md +++ b/.github/RELEASE.md @@ -2,7 +2,7 @@ This is a guide to know the steps to create a new release. -1. Update the version in [DEPLOY_VERSION](../deploy) +1. Update the version in [DEPLOY_VERSION](../src/version.txt) 1. Update the version in [CHANGELOG.md](../CHANGELOG.md) 1. Build the project `./build.sh bin` - This generates `bin/main` & `bin/checksum` 1. Create a [new release](https://github.com/Purpose-Green/deploy/releases/new) from GitHub diff --git a/deploy b/deploy index b7d7c60..770df11 100755 --- a/deploy +++ b/deploy @@ -1,9 +1,6 @@ #!/bin/bash set -euo pipefail -# shellcheck disable=SC2034 -declare -r DEPLOY_VERSION="0.1.0" - DEPLOY_ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" export DEPLOY_ROOT_DIR diff --git a/src/console_header.sh b/src/console_header.sh index d76a472..ffc76af 100644 --- a/src/console_header.sh +++ b/src/console_header.sh @@ -2,7 +2,7 @@ set -o allexport function console_header::print_version() { - printf "%s\n" "$DEPLOY_VERSION" + printf "%s\n" "$(cat "$(dirname "${BASH_SOURCE[0]}")"/version.txt)" } function console_header::print_help() { diff --git a/src/main.sh b/src/main.sh index 4a33626..4596de8 100644 --- a/src/main.sh +++ b/src/main.sh @@ -71,7 +71,6 @@ function main::update_development() { main::force_checkout "$development" main::merge_source_to_target "remotes/origin/$target" "$development" - } function main::merge_source_to_target() { diff --git a/src/version.txt b/src/version.txt new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/src/version.txt @@ -0,0 +1 @@ +0.1.0 From f9c3ac9a963207c419f4f38710de6f3acc29308c Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 08:58:43 +0200 Subject: [PATCH 3/8] feat: add --new option on build.sh --- build.sh | 50 +++++- local/checksum | 1 + local/deploy | 447 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 local/checksum create mode 100755 local/deploy diff --git a/build.sh b/build.sh index 5e6922c..d7726e8 100755 --- a/build.sh +++ b/build.sh @@ -49,10 +49,58 @@ function generate_checksum() { echo "$checksum" } +function update_version() { + local version_type=$1 + local version_file=$2 + + local current_version + current_version=$(cat "$version_file") + IFS='.' read -r major minor patch <<< "$current_version" + + case "$version_type" in + major) + major=$((major + 1)) + ;; + minor) + minor=$((minor + 1)) + ;; + patch) + patch=$((patch + 1)) + ;; + *) + echo "Invalid version increment option: $version_type. Use major, minor, or patch." + exit 1 + ;; + esac + + local new_version="$major.$minor.$patch" + echo "$new_version" > "$version_file" + echo "Version updated to $new_version" +} + ######################## # MAIN # ######################## -OUT_DIR=${1:-"bin"} +OUT_DIR="bin" +NEW_VERSION_TYPE="" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --new) + shift + NEW_VERSION_TYPE="$1" + ;; + *) + OUT_DIR="$1" + ;; + esac + shift +done + +if [[ "$NEW_VERSION_TYPE" != "" ]]; then + update_version "$NEW_VERSION_TYPE" "src/version.txt" +fi mkdir -p "$OUT_DIR" build "$OUT_DIR/deploy" diff --git a/local/checksum b/local/checksum new file mode 100644 index 0000000..299bc77 --- /dev/null +++ b/local/checksum @@ -0,0 +1 @@ +f972bf56d22d59324bbf66e34840313fab66fde3b75a4350a42a5987ce020676 local/deploy diff --git a/local/deploy b/local/deploy new file mode 100755 index 0000000..ddfc4f1 --- /dev/null +++ b/local/deploy @@ -0,0 +1,447 @@ +#!/bin/bash +# src/check_os.sh +set -o allexport + +# shellcheck disable=SC2034 +_OS="Unknown" + +if [[ "$(uname)" == "Linux" ]]; then + _OS="Linux" +elif [[ "$(uname)" == "Darwin" ]]; then + _OS="OSX" +elif [[ $(uname) == *"MINGW"* ]]; then + _OS="Windows" +fi + +# src/colors.sh +set -o allexport + +export COLOR_RED="\033[1;31m" +export COLOR_GREEN="\033[1;32m" +export COLOR_YELLOW="\033[1;33m" +export COLOR_BLUE="\033[1;34m" +export COLOR_PURPLE="\033[1;35m" +export COLOR_CYAN="\033[1;36m" +export COLOR_ORANGE="\033[38;5;214m" +export COLOR_RESET="\033[0m" + +# src/compare.sh +set -euo pipefail + +# shellcheck disable=SC2005 + +function compare::source_with_target() { + local source=$1 + local target=$2 + + echo -e "Comparing ${COLOR_ORANGE}$source${COLOR_RESET} with ${COLOR_ORANGE}$target${COLOR_RESET}" + echo -e "${COLOR_BLUE}------------------------------------------------------------------${COLOR_RESET}" + echo -e "Commits to include in the release (into ${COLOR_ORANGE}$target${COLOR_RESET}):" + echo "$(git log --color --oneline origin/"$target".."$source")" + echo -e "${COLOR_BLUE}------------------------------------------------------------------${COLOR_RESET}" + echo -e "Changed files between '${COLOR_ORANGE}$target${COLOR_RESET}' and '${COLOR_ORANGE}$source${COLOR_RESET}':" + compare::render_changed_files "$source" "$target" +} + +function compare::render_changed_files() { + local source=$1 + local target=$2 + + local added_files=() + local modified_files=() + local deleted_files=() + + # Collect files based on their status + while read -r status file; do + case "$status" in + A) # Added (created) + added_files+=("$file") + ;; + M) # Modified (updated) + modified_files+=("$file") + ;; + D) # Deleted + deleted_files+=("$file") + ;; + esac + done < <(git diff --name-status "$target".."$source") + + # Output the files, sorted by status + + # Added (created) files + if [ "${#added_files[@]}" -gt 0 ]; then + for file in "${added_files[@]}"; do + echo -e "${COLOR_GREEN}+ $file${COLOR_RESET}" + done + fi + + # Modified (updated) files + if [ "${#modified_files[@]}" -gt 0 ]; then + for file in "${modified_files[@]}"; do + echo -e "${COLOR_YELLOW}~ $file${COLOR_RESET}" + done + fi + + + # Deleted files + if [ "${#deleted_files[@]}" -gt 0 ]; then + for file in "${deleted_files[@]}"; do + echo -e "${COLOR_RED}- $file${COLOR_RESET}" + done + fi +} + +# src/console_header.sh +set -o allexport + +function console_header::print_version() { + printf "%s\n" "$(cat "$(dirname "${BASH_SOURCE[0]}")"/version.txt)" +} + +function console_header::print_help() { + cat </dev/null || echo "v0") + + echo -e "Current latest tag: ${COLOR_CYAN}$latest_tag${COLOR_RESET}" + local new_tag=$(release::generate_new_tag "$latest_tag" "$changed_files") + compare::source_with_target "$source" "$target" + + # shellcheck disable=SC2116 + local question=$(echo "Force checkout ${COLOR_ORANGE}origin/$target${COLOR_RESET}" \ + "and create new tag ${COLOR_CYAN}$new_tag${COLOR_RESET}... Ready to start?") + io::confirm_or_exit "$question" + + if [ -z "$changed_files" ]; then + echo -e "${COLOR_YELLOW}No files changed between branches, skipping merge.${COLOR_RESET}" + exit 0 + fi + + main::force_checkout "$target" + main::merge_source_to_target "$source" "$target" + + release::create_tag "$new_tag" "$changed_files" + release::create_github_release "$latest_tag" "$new_tag" + + main::update_development "$development" "$target" +} + +function main::render_steps() { + local source=$1 + local target=$1 + local development=$2 + + echo "This script will automate the release process and follow the following steps:" + echo "- Define the branch to deploy: $source" + echo "- Fetch latest remote changes" + echo "- Compare the branch with $target to view the commits that will be deployed" + echo "- Confirm you wish to proceed" + echo "- Merge the selected branch to $target" + echo "- Create a tag and release" + echo "- Merge the selected branch back to $development" + echo "" + echo "This script must use your local git environment." +} + +function main::update_development() { + local development=$1 + local target=$2 + + echo -e "Merging ${COLOR_ORANGE}$target${COLOR_RESET} back to" \ + "${COLOR_ORANGE}$development${COLOR_RESET} (increase the release contains hotfixes" \ + "that are not in ${COLOR_ORANGE}$development${COLOR_RESET})" + + main::force_checkout "$development" + main::merge_source_to_target "remotes/origin/$target" "$development" +} + +function main::merge_source_to_target() { + local source=$1 + local target=$2 + + echo -e "Merging ${COLOR_ORANGE}$source${COLOR_RESET} release to ${COLOR_ORANGE}$target${COLOR_RESET}" + + if [[ "$DRY_RUN" == true ]]; then + echo -e "${COLOR_CYAN}--dry-run enabled. Skipping git merge ($source into $target)${COLOR_RESET}" + return + fi + + if ! git merge "$source"; then + echo -e "${COLOR_RED}Merge failed. Please resolve conflicts and try again.${COLOR_RESET}" + exit 1 + fi + + git push origin "$target" --no-verify + +} + +function main::force_checkout() { + if [[ "$DRY_RUN" == true ]]; then + echo -e "${COLOR_CYAN}--dry-run enabled. Skipping git checkout${COLOR_RESET}" + return + fi + + git config advice.detachedHead false + [ -f .git/hooks/post-checkout ] && mv .git/hooks/post-checkout .git/hooks/post-checkout.bak + git checkout -f origin/"$1" + git branch -D "$1" + git checkout -b "$1" origin/"$1" + [ -f .git/hooks/post-checkout.bak ] && mv .git/hooks/post-checkout.bak .git/hooks/post-checkout + git config advice.detachedHead true +} + +# src/release.sh +set -euo pipefail + +function release::generate_new_tag() { + local latest_tag=$1 + local changed_files=$2 + + local tag_number + if [[ $latest_tag =~ ^v([0-9]+)$ ]]; then + tag_number="${BASH_REMATCH[1]}" + tag_number=$((tag_number + 1)) + else + tag_number=1 + fi + + echo "v$tag_number" +} + +function release::create_tag() { + local new_tag=$1 + local changed_files=$2 + + if [[ "$DRY_RUN" == true ]]; then + echo -e "${COLOR_CYAN}--dry-run enabled. Skipping creating a tag ($new_tag)${COLOR_RESET}" + return + fi + + git tag -a "$new_tag" -m "Release $new_tag + +Changes: +$changed_files" + + git push origin --tags --no-verify +} + +# shellcheck disable=SC2155 +function release::create_github_release() { + if [ "$GH_CLI_INSTALLED" = false ]; then + return + fi + + local previous_tag=$1 + local new_tag=$2 + + if [ "$previous_tag" = "v0" ]; then + previous_tag="main" + fi + + local release_name=$(release::generate_release_name) + local remote_url=$(git remote get-url origin) + local repo_info=$(echo "$remote_url" | sed -E 's|git@github\.com:||; s|\.git$||') + + local changelog_url="https://github.com/$repo_info/compare/$previous_tag...$new_tag" + local full_changelog="**Full Changelog**: $changelog_url" + + if [[ "$DRY_RUN" == true ]]; then + echo -e "${COLOR_CYAN}--dry-run enabled. Skipping creating a release ($release_name)${COLOR_RESET}" + return + fi + + local commits=$(git log --oneline "$previous_tag".."$new_tag") + + gh release create "$new_tag" \ + --title "$release_name" \ + --notes "$(echo -e "$commits\n\n$full_changelog")" +} + +# shellcheck disable=SC2155 +function release::generate_release_name() { + local current_date=$(date +"%Y-%m-%d") + # Use xargs to trim leading/trailing whitespace + local latest_release=$(gh release list | head -n 1 | awk -F 'Latest' '{print $1}' | xargs) + + local release_number + if [[ "$latest_release" =~ ^$current_date\ #([0-9]+)$ ]]; then + release_number=$((BASH_REMATCH[1] + 1)) + else + release_number=1 + fi + + echo "$current_date #$release_number" +} + +# src/validate.sh +set -euo pipefail + +function validate::no_diff_between_local_and_origin() { + local source=$1 + local target=$2 + local force_deploy=$3 + + # Check the status of the local branch compared to origin/main + ahead_commits=$(git rev-list --count HEAD ^origin/main) + + if [[ "$ahead_commits" -gt 0 && "$force_deploy" == false ]]; then + echo -e "${COLOR_RED}Error: Your $source is ahead of 'origin/$source'" \ + "by $ahead_commits commit(s)${COLOR_RESET}." + + echo -e "${COLOR_YELLOW}Please push your changes or reset \ +your${COLOR_RESET} ${COLOR_ORANGE}$source${COLOR_RESET}." + + exit 1 + fi + + if [[ "$ahead_commits" -gt 0 && "$force_deploy" == true ]]; then + echo -e "Your local ${COLOR_ORANGE}$source${COLOR_RESET} is ahead" \ + "of ${COLOR_ORANGE}origin/$source${COLOR_RESET}" \ + "by ${COLOR_RED}$ahead_commits${COLOR_RESET} commit(s)${COLOR_RESET}." + + # shellcheck disable=SC2155 + # shellcheck disable=SC2116 + local question=$(echo "${COLOR_YELLOW}Are you sure you want to push them" \ + "to 'origin/$target' as part of the release?${COLOR_RESET}") + + io::confirm_or_exit "$question" + fi +} + +#!/bin/bash +set -euo pipefail + +DEPLOY_ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" +export DEPLOY_ROOT_DIR + + +# Check if at least one argument (branch name) is passed +if [ $# -lt 1 ]; then + console_header::print_help + exit 1 +fi + +FORCE_DEPLOY=false +SOURCE_BRANCH=${SOURCE_BRANCH:-"main"} +TARGET_BRANCH=${TARGET_BRANCH:-"prod"} +DEVELOPMENT_BRANCH=${DEVELOPMENT_BRANCH:-"main"} +DEPLOY_SUCCESSFUL_TEXT=${DEPLOY_SUCCESSFUL_TEXT:-} +DRY_RUN=${DRY_RUN:-false} + +while [[ $# -gt 0 ]]; do + argument="$1" + case $argument in + --debug) + set -x + ;; + --dry-run) + DRY_RUN=true + ;; + --help) + console_header::print_help + exit 0 + ;; + -v|--version) + console_header::print_version + exit 0 + ;; + -s|--source) + SOURCE_BRANCH="$2" + shift + ;; + -t|--target) + TARGET_BRANCH="$2" + shift + ;; + -d|--development) + DEVELOPMENT_BRANCH="$2" + shift + ;; + --force) + FORCE_DEPLOY=true + ;; + esac + shift +done + +GH_CLI_INSTALLED=false +if command -v gh &> /dev/null; then + GH_CLI_INSTALLED=true +fi + +export GH_CLI_INSTALLED +export DRY_RUN + + +main::action "$SOURCE_BRANCH" \ + "$TARGET_BRANCH" \ + "$DEVELOPMENT_BRANCH" \ + "$FORCE_DEPLOY" + +echo -e "${COLOR_GREEN}Script completed${COLOR_RESET}" +if [ -n "$DEPLOY_SUCCESSFUL_TEXT" ]; then + echo -e "$DEPLOY_SUCCESSFUL_TEXT" +fi From 5c1bfe5cd27a8a33600c1dd4387ebbb4065be36c Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 09:03:25 +0200 Subject: [PATCH 4/8] refactor: remove local folder it was created for testing purposes. I will add it to ignore --- local/checksum | 1 - local/deploy | 447 ------------------------------------------------- 2 files changed, 448 deletions(-) delete mode 100644 local/checksum delete mode 100755 local/deploy diff --git a/local/checksum b/local/checksum deleted file mode 100644 index 299bc77..0000000 --- a/local/checksum +++ /dev/null @@ -1 +0,0 @@ -f972bf56d22d59324bbf66e34840313fab66fde3b75a4350a42a5987ce020676 local/deploy diff --git a/local/deploy b/local/deploy deleted file mode 100755 index ddfc4f1..0000000 --- a/local/deploy +++ /dev/null @@ -1,447 +0,0 @@ -#!/bin/bash -# src/check_os.sh -set -o allexport - -# shellcheck disable=SC2034 -_OS="Unknown" - -if [[ "$(uname)" == "Linux" ]]; then - _OS="Linux" -elif [[ "$(uname)" == "Darwin" ]]; then - _OS="OSX" -elif [[ $(uname) == *"MINGW"* ]]; then - _OS="Windows" -fi - -# src/colors.sh -set -o allexport - -export COLOR_RED="\033[1;31m" -export COLOR_GREEN="\033[1;32m" -export COLOR_YELLOW="\033[1;33m" -export COLOR_BLUE="\033[1;34m" -export COLOR_PURPLE="\033[1;35m" -export COLOR_CYAN="\033[1;36m" -export COLOR_ORANGE="\033[38;5;214m" -export COLOR_RESET="\033[0m" - -# src/compare.sh -set -euo pipefail - -# shellcheck disable=SC2005 - -function compare::source_with_target() { - local source=$1 - local target=$2 - - echo -e "Comparing ${COLOR_ORANGE}$source${COLOR_RESET} with ${COLOR_ORANGE}$target${COLOR_RESET}" - echo -e "${COLOR_BLUE}------------------------------------------------------------------${COLOR_RESET}" - echo -e "Commits to include in the release (into ${COLOR_ORANGE}$target${COLOR_RESET}):" - echo "$(git log --color --oneline origin/"$target".."$source")" - echo -e "${COLOR_BLUE}------------------------------------------------------------------${COLOR_RESET}" - echo -e "Changed files between '${COLOR_ORANGE}$target${COLOR_RESET}' and '${COLOR_ORANGE}$source${COLOR_RESET}':" - compare::render_changed_files "$source" "$target" -} - -function compare::render_changed_files() { - local source=$1 - local target=$2 - - local added_files=() - local modified_files=() - local deleted_files=() - - # Collect files based on their status - while read -r status file; do - case "$status" in - A) # Added (created) - added_files+=("$file") - ;; - M) # Modified (updated) - modified_files+=("$file") - ;; - D) # Deleted - deleted_files+=("$file") - ;; - esac - done < <(git diff --name-status "$target".."$source") - - # Output the files, sorted by status - - # Added (created) files - if [ "${#added_files[@]}" -gt 0 ]; then - for file in "${added_files[@]}"; do - echo -e "${COLOR_GREEN}+ $file${COLOR_RESET}" - done - fi - - # Modified (updated) files - if [ "${#modified_files[@]}" -gt 0 ]; then - for file in "${modified_files[@]}"; do - echo -e "${COLOR_YELLOW}~ $file${COLOR_RESET}" - done - fi - - - # Deleted files - if [ "${#deleted_files[@]}" -gt 0 ]; then - for file in "${deleted_files[@]}"; do - echo -e "${COLOR_RED}- $file${COLOR_RESET}" - done - fi -} - -# src/console_header.sh -set -o allexport - -function console_header::print_version() { - printf "%s\n" "$(cat "$(dirname "${BASH_SOURCE[0]}")"/version.txt)" -} - -function console_header::print_help() { - cat </dev/null || echo "v0") - - echo -e "Current latest tag: ${COLOR_CYAN}$latest_tag${COLOR_RESET}" - local new_tag=$(release::generate_new_tag "$latest_tag" "$changed_files") - compare::source_with_target "$source" "$target" - - # shellcheck disable=SC2116 - local question=$(echo "Force checkout ${COLOR_ORANGE}origin/$target${COLOR_RESET}" \ - "and create new tag ${COLOR_CYAN}$new_tag${COLOR_RESET}... Ready to start?") - io::confirm_or_exit "$question" - - if [ -z "$changed_files" ]; then - echo -e "${COLOR_YELLOW}No files changed between branches, skipping merge.${COLOR_RESET}" - exit 0 - fi - - main::force_checkout "$target" - main::merge_source_to_target "$source" "$target" - - release::create_tag "$new_tag" "$changed_files" - release::create_github_release "$latest_tag" "$new_tag" - - main::update_development "$development" "$target" -} - -function main::render_steps() { - local source=$1 - local target=$1 - local development=$2 - - echo "This script will automate the release process and follow the following steps:" - echo "- Define the branch to deploy: $source" - echo "- Fetch latest remote changes" - echo "- Compare the branch with $target to view the commits that will be deployed" - echo "- Confirm you wish to proceed" - echo "- Merge the selected branch to $target" - echo "- Create a tag and release" - echo "- Merge the selected branch back to $development" - echo "" - echo "This script must use your local git environment." -} - -function main::update_development() { - local development=$1 - local target=$2 - - echo -e "Merging ${COLOR_ORANGE}$target${COLOR_RESET} back to" \ - "${COLOR_ORANGE}$development${COLOR_RESET} (increase the release contains hotfixes" \ - "that are not in ${COLOR_ORANGE}$development${COLOR_RESET})" - - main::force_checkout "$development" - main::merge_source_to_target "remotes/origin/$target" "$development" -} - -function main::merge_source_to_target() { - local source=$1 - local target=$2 - - echo -e "Merging ${COLOR_ORANGE}$source${COLOR_RESET} release to ${COLOR_ORANGE}$target${COLOR_RESET}" - - if [[ "$DRY_RUN" == true ]]; then - echo -e "${COLOR_CYAN}--dry-run enabled. Skipping git merge ($source into $target)${COLOR_RESET}" - return - fi - - if ! git merge "$source"; then - echo -e "${COLOR_RED}Merge failed. Please resolve conflicts and try again.${COLOR_RESET}" - exit 1 - fi - - git push origin "$target" --no-verify - -} - -function main::force_checkout() { - if [[ "$DRY_RUN" == true ]]; then - echo -e "${COLOR_CYAN}--dry-run enabled. Skipping git checkout${COLOR_RESET}" - return - fi - - git config advice.detachedHead false - [ -f .git/hooks/post-checkout ] && mv .git/hooks/post-checkout .git/hooks/post-checkout.bak - git checkout -f origin/"$1" - git branch -D "$1" - git checkout -b "$1" origin/"$1" - [ -f .git/hooks/post-checkout.bak ] && mv .git/hooks/post-checkout.bak .git/hooks/post-checkout - git config advice.detachedHead true -} - -# src/release.sh -set -euo pipefail - -function release::generate_new_tag() { - local latest_tag=$1 - local changed_files=$2 - - local tag_number - if [[ $latest_tag =~ ^v([0-9]+)$ ]]; then - tag_number="${BASH_REMATCH[1]}" - tag_number=$((tag_number + 1)) - else - tag_number=1 - fi - - echo "v$tag_number" -} - -function release::create_tag() { - local new_tag=$1 - local changed_files=$2 - - if [[ "$DRY_RUN" == true ]]; then - echo -e "${COLOR_CYAN}--dry-run enabled. Skipping creating a tag ($new_tag)${COLOR_RESET}" - return - fi - - git tag -a "$new_tag" -m "Release $new_tag - -Changes: -$changed_files" - - git push origin --tags --no-verify -} - -# shellcheck disable=SC2155 -function release::create_github_release() { - if [ "$GH_CLI_INSTALLED" = false ]; then - return - fi - - local previous_tag=$1 - local new_tag=$2 - - if [ "$previous_tag" = "v0" ]; then - previous_tag="main" - fi - - local release_name=$(release::generate_release_name) - local remote_url=$(git remote get-url origin) - local repo_info=$(echo "$remote_url" | sed -E 's|git@github\.com:||; s|\.git$||') - - local changelog_url="https://github.com/$repo_info/compare/$previous_tag...$new_tag" - local full_changelog="**Full Changelog**: $changelog_url" - - if [[ "$DRY_RUN" == true ]]; then - echo -e "${COLOR_CYAN}--dry-run enabled. Skipping creating a release ($release_name)${COLOR_RESET}" - return - fi - - local commits=$(git log --oneline "$previous_tag".."$new_tag") - - gh release create "$new_tag" \ - --title "$release_name" \ - --notes "$(echo -e "$commits\n\n$full_changelog")" -} - -# shellcheck disable=SC2155 -function release::generate_release_name() { - local current_date=$(date +"%Y-%m-%d") - # Use xargs to trim leading/trailing whitespace - local latest_release=$(gh release list | head -n 1 | awk -F 'Latest' '{print $1}' | xargs) - - local release_number - if [[ "$latest_release" =~ ^$current_date\ #([0-9]+)$ ]]; then - release_number=$((BASH_REMATCH[1] + 1)) - else - release_number=1 - fi - - echo "$current_date #$release_number" -} - -# src/validate.sh -set -euo pipefail - -function validate::no_diff_between_local_and_origin() { - local source=$1 - local target=$2 - local force_deploy=$3 - - # Check the status of the local branch compared to origin/main - ahead_commits=$(git rev-list --count HEAD ^origin/main) - - if [[ "$ahead_commits" -gt 0 && "$force_deploy" == false ]]; then - echo -e "${COLOR_RED}Error: Your $source is ahead of 'origin/$source'" \ - "by $ahead_commits commit(s)${COLOR_RESET}." - - echo -e "${COLOR_YELLOW}Please push your changes or reset \ -your${COLOR_RESET} ${COLOR_ORANGE}$source${COLOR_RESET}." - - exit 1 - fi - - if [[ "$ahead_commits" -gt 0 && "$force_deploy" == true ]]; then - echo -e "Your local ${COLOR_ORANGE}$source${COLOR_RESET} is ahead" \ - "of ${COLOR_ORANGE}origin/$source${COLOR_RESET}" \ - "by ${COLOR_RED}$ahead_commits${COLOR_RESET} commit(s)${COLOR_RESET}." - - # shellcheck disable=SC2155 - # shellcheck disable=SC2116 - local question=$(echo "${COLOR_YELLOW}Are you sure you want to push them" \ - "to 'origin/$target' as part of the release?${COLOR_RESET}") - - io::confirm_or_exit "$question" - fi -} - -#!/bin/bash -set -euo pipefail - -DEPLOY_ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" -export DEPLOY_ROOT_DIR - - -# Check if at least one argument (branch name) is passed -if [ $# -lt 1 ]; then - console_header::print_help - exit 1 -fi - -FORCE_DEPLOY=false -SOURCE_BRANCH=${SOURCE_BRANCH:-"main"} -TARGET_BRANCH=${TARGET_BRANCH:-"prod"} -DEVELOPMENT_BRANCH=${DEVELOPMENT_BRANCH:-"main"} -DEPLOY_SUCCESSFUL_TEXT=${DEPLOY_SUCCESSFUL_TEXT:-} -DRY_RUN=${DRY_RUN:-false} - -while [[ $# -gt 0 ]]; do - argument="$1" - case $argument in - --debug) - set -x - ;; - --dry-run) - DRY_RUN=true - ;; - --help) - console_header::print_help - exit 0 - ;; - -v|--version) - console_header::print_version - exit 0 - ;; - -s|--source) - SOURCE_BRANCH="$2" - shift - ;; - -t|--target) - TARGET_BRANCH="$2" - shift - ;; - -d|--development) - DEVELOPMENT_BRANCH="$2" - shift - ;; - --force) - FORCE_DEPLOY=true - ;; - esac - shift -done - -GH_CLI_INSTALLED=false -if command -v gh &> /dev/null; then - GH_CLI_INSTALLED=true -fi - -export GH_CLI_INSTALLED -export DRY_RUN - - -main::action "$SOURCE_BRANCH" \ - "$TARGET_BRANCH" \ - "$DEVELOPMENT_BRANCH" \ - "$FORCE_DEPLOY" - -echo -e "${COLOR_GREEN}Script completed${COLOR_RESET}" -if [ -n "$DEPLOY_SUCCESSFUL_TEXT" ]; then - echo -e "$DEPLOY_SUCCESSFUL_TEXT" -fi From 7569830c1bfa4c1440184d289e4309737b74ed7f Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 09:06:52 +0200 Subject: [PATCH 5/8] docs: update release docs --- .github/RELEASE.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/RELEASE.md b/.github/RELEASE.md index 5ba0a86..9e48307 100644 --- a/.github/RELEASE.md +++ b/.github/RELEASE.md @@ -2,8 +2,10 @@ This is a guide to know the steps to create a new release. -1. Update the version in [DEPLOY_VERSION](../src/version.txt) -1. Update the version in [CHANGELOG.md](../CHANGELOG.md) 1. Build the project `./build.sh bin` - This generates `bin/main` & `bin/checksum` -1. Create a [new release](https://github.com/Purpose-Green/deploy/releases/new) from GitHub -1. Attach `bin/main` and `bin/checksum` to the release +1. Make sure you got the version in `src/version.txt` up to date + 1. You can update this using `./build.sh bin --new major|minor|patch` +1. Update the version in [CHANGELOG.md](../CHANGELOG.md) +1. Run `bin/deploy` +1. Attach `bin/main` and `bin/checksum` to the latest release + 1. https://github.com/Purpose-Green/deploy/releases From d82fecd28153173e9df99e1088b9608e2c1c5a2c Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 09:09:55 +0200 Subject: [PATCH 6/8] docs: update .env ading create-pr vars --- .env | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.env b/.env index 3218831..2b3d999 100644 --- a/.env +++ b/.env @@ -1,3 +1,8 @@ +# create-pr +PR_TICKET_LINK_PREFIX="https://github.com/Purpose-Green/deploy/issues" +PR_LINK_PREFIX_TEXT="Closes: " + # bashunit BASHUNIT_DEFAULT_PATH="tests" BASHUNIT_TESTS_ENV="tests/helpers.sh" + From c1ea6862a707a11693677de0ae97a10375123024 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 09:18:14 +0200 Subject: [PATCH 7/8] refactor: use global DEPLOY_VERSION instead of src/version.txt --- .github/RELEASE.md | 6 +++--- build.sh | 30 +++++++++++++++++++++++++----- deploy | 3 +++ src/version.txt | 1 - 4 files changed, 31 insertions(+), 9 deletions(-) delete mode 100644 src/version.txt diff --git a/.github/RELEASE.md b/.github/RELEASE.md index 9e48307..0a7783d 100644 --- a/.github/RELEASE.md +++ b/.github/RELEASE.md @@ -3,9 +3,9 @@ This is a guide to know the steps to create a new release. 1. Build the project `./build.sh bin` - This generates `bin/main` & `bin/checksum` -1. Make sure you got the version in `src/version.txt` up to date - 1. You can update this using `./build.sh bin --new major|minor|patch` +1. Make sure the `DEPLOY_VERSION` is up to date in [deploy](./deploy) entry point + 1. You can update this using `./build.sh bin --new major|minor|patch` 1. Update the version in [CHANGELOG.md](../CHANGELOG.md) 1. Run `bin/deploy` 1. Attach `bin/main` and `bin/checksum` to the latest release - 1. https://github.com/Purpose-Green/deploy/releases + 1. https://github.com/Purpose-Green/deploy/releases diff --git a/build.sh b/build.sh index d7726e8..03ff841 100755 --- a/build.sh +++ b/build.sh @@ -49,14 +49,23 @@ function generate_checksum() { echo "$checksum" } +function get_current_version() { + local file_with_version=$1 + grep "declare -r $VERSION_VAR_NAME=" "$file_with_version" \ + | sed "s/declare -r $VERSION_VAR_NAME=\"\([0-9]*\.[0-9]*\.[0-9]*\)\"/\1/" +} + function update_version() { local version_type=$1 - local version_file=$2 + local file_with_version=$2 local current_version - current_version=$(cat "$version_file") + current_version=$(grep "declare -r $VERSION_VAR_NAME=" "$file_with_version" \ + | sed "s/declare -r $VERSION_VAR_NAME=\"\([0-9]*\.[0-9]*\.[0-9]*\)\"/\1/") + IFS='.' read -r major minor patch <<< "$current_version" + # Increment the appropriate version part case "$version_type" in major) major=$((major + 1)) @@ -74,13 +83,22 @@ function update_version() { esac local new_version="$major.$minor.$patch" - echo "$new_version" > "$version_file" - echo "Version updated to $new_version" + local search_pattern="declare -r $VERSION_VAR_NAME=\"[0-9]*\.[0-9]*\.[0-9]*\"" + local replace_pattern="declare -r $VERSION_VAR_NAME=\"$new_version\"" + + sed -i.bak \ + "s/$search_pattern/$replace_pattern/" \ + "$file_with_version" + + rm "${file_with_version}.bak" + + echo "$new_version" } ######################## # MAIN # ######################## +VERSION_VAR_NAME="DEPLOY_VERSION" OUT_DIR="bin" NEW_VERSION_TYPE="" @@ -99,7 +117,9 @@ while [[ $# -gt 0 ]]; do done if [[ "$NEW_VERSION_TYPE" != "" ]]; then - update_version "$NEW_VERSION_TYPE" "src/version.txt" + echo "Updated version: $(update_version "$NEW_VERSION_TYPE" "deploy")" +else + echo "Current version: $(get_current_version "deploy")" fi mkdir -p "$OUT_DIR" diff --git a/deploy b/deploy index 770df11..b7d7c60 100755 --- a/deploy +++ b/deploy @@ -1,6 +1,9 @@ #!/bin/bash set -euo pipefail +# shellcheck disable=SC2034 +declare -r DEPLOY_VERSION="0.1.0" + DEPLOY_ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" export DEPLOY_ROOT_DIR diff --git a/src/version.txt b/src/version.txt deleted file mode 100644 index 6e8bf73..0000000 --- a/src/version.txt +++ /dev/null @@ -1 +0,0 @@ -0.1.0 From d5d334aa40f0de251bb0a33352bf0a3121ad7e10 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 18 Sep 2024 09:46:29 +0200 Subject: [PATCH 8/8] update changelog --- CHANGELOG.md | 6 +++++- README.md | 3 ++- src/console_header.sh | 1 + .../snapshots/main_test_sh.test_main_without_args.snapshot | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d244ea..e0e55fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog -## [0.1](https://github.com/Chemaclass/bash-skeleton/compare/main...0.1) - 2024-09-15 +## Unreleased + +- Add semantic versioning + +## [0.1](https://github.com/Purpose-Green/deploy/compare/main...0.1) - 2024-09-17 Initial release. Check README for instructions about installation and how to use it. diff --git a/README.md b/README.md index e2717c4..f09cce5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This script automates deployment using your local Git. It: ## How to use it? -```bash +```txt ./deploy --help Usage: deploy [arguments] [options] @@ -27,6 +27,7 @@ Options: --debug Enable debug mode (set -x). --dry-run Simulate the deployment process without making any changes. --force Ignore that your current local branch has ahead commits. + -v|-version Display current version. -s, --source Specify the source branch. -t, --target Specify the target branch. -d, --development Specify the development branch. diff --git a/src/console_header.sh b/src/console_header.sh index ffc76af..6af80ec 100644 --- a/src/console_header.sh +++ b/src/console_header.sh @@ -18,6 +18,7 @@ Options: --debug Enable debug mode (set -x). --dry-run Simulate the deployment process without making any changes. --force Ignore that your current local branch has ahead commits. + -v|--version Display current version. -s, --source Specify the source branch. -t, --target Specify the target branch. -d, --development Specify the development branch. diff --git a/tests/e2e/snapshots/main_test_sh.test_main_without_args.snapshot b/tests/e2e/snapshots/main_test_sh.test_main_without_args.snapshot index 5ef15eb..a46050d 100644 --- a/tests/e2e/snapshots/main_test_sh.test_main_without_args.snapshot +++ b/tests/e2e/snapshots/main_test_sh.test_main_without_args.snapshot @@ -9,6 +9,7 @@ Options: --debug Enable debug mode (set -x). --dry-run Simulate the deployment process without making any changes. --force Ignore that your current local branch has ahead commits. + -v|--version Display current version. -s, --source Specify the source branch. -t, --target Specify the target branch. -d, --development Specify the development branch.