diff --git a/README.md b/README.md index 7f725fb..f814cdb 100644 --- a/README.md +++ b/README.md @@ -83,11 +83,68 @@ _For running an S3 service locally._ --- ## Scripts + Inside the `scripts` folder you will find one-off scripts to help with tasks. * `db_migrate.sh` - Helps migrate databases between versions of mysql. +## CLI Tooling Setup + +Add the `bin` directory to your path to use **Hop** and **Git Scripts**. + +## Hop + +A script that makes it easy to hop into your project containers and run commands. + +## Git Scripts + +Custom scripts that extend Git functionality, to streamline the process of tracking tickets and managing releases + +### `git-tickets` + +This command is used to get the tickets since staging was last updated. +By default, it does not update the branches. + +```shell +git tickets [options] [arguments] +``` + +| Options | Description | Default | +|----------|-----------------------------------------------------------------|---------| +| --update | Update the specified branches from the remote before comparison | N/A | + +| Arguments | Description | Default | Any of | +|-----------|--------------------------------------|---------|------------| +| branch 1 | the target branch that is up to date | master | any branch | +| branch 2 | the branch that is behind | staging | any branch | + +### Tickets Example + +```shell + git tickets --update master staging +``` + +### `git-make-release` + +This command automates the process of preparing a new software release. +It creates a release branch from the current branch, increments the version number, updates the `CHANGELOG.md` + +```shell + git make-release [options] +``` + +| Options | Description | Default | +|---------|-----------------------------------------------------------|---------| +| --dry | Perform a dry run without any changes to branches or tags | N/A | + +### Make Release Example + +```shell +git make-release --dry +``` + ## Docs + * [Hop](docs/hop/README.md) * [Setting up Nginx-Proxy](docs/nginx-proxy/README.md) * [Setting up PHP Testing in PhpStorm](docs/phpstorm-docker/README.md) diff --git a/bin/git-make-release b/bin/git-make-release new file mode 100755 index 0000000..4350fd5 --- /dev/null +++ b/bin/git-make-release @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +# Prompt for the version number +prompt_for_version() { + read -rp "Enter the version number (default: $1): " version + echo "${version:-$1}" # Return the entered version number or the default if none was entered +} + +# Increment version number +increment_version() { + # Split the version string into parts using read -a + IFS='.' + read -ra version_parts <<< "$1" + + # Ensure that we have exactly three parts for major, minor, and patch versions + if [ ${#version_parts[@]} -ne 3 ]; then + echo "Error: Invalid version format '$1'. Expected format 'Major.Minor.Patch'." >&2 + return 1 # Exit the function with an error status + fi + + # Increment the minor version and reset the patch version to 0 + local next_version="${version_parts[0]}.$((version_parts[1] + 1)).0" + + # Call prompt_for_version, using the next version as the default + prompt_for_version "$next_version" +} + +# Get the latest version tag +get_latest_version() { + git describe --tags "$(git rev-list --tags --max-count=1)" 2>/dev/null || echo "v0.0.0" +} + +# Prepend the tickets to the CHANGELOG.md +prepend_to_changelog() { + local version=$1 + local tickets=$2 + local date + + date=$(date +"%b %d, %Y") + local changelog="CHANGELOG.md" + + # Create a backup of the CHANGELOG.md + cp "$changelog" "$changelog.bak" + + # Prepend the new content to the CHANGELOG.md + { + echo "# v$version ($date)" + for ticket in $tickets; do + echo "* $ticket - " + done + echo "" + cat "$changelog.bak" + } > "$changelog" + + rm "$changelog.bak" +} + +# Check if the --dry flag is set +DRY_RUN=false +if [ "$1" == "--dry" ]; then + DRY_RUN=true +fi + +# Get the latest tag and suggest the next version number +LATEST_TAG=$(get_latest_version) +NEXT_VERSION=$(increment_version "${LATEST_TAG#v}") # Assuming the tag is in the 'v1.2.3' format + +if $DRY_RUN; then + # Perform a dry run + echo "This is a dry run. The release branch will not be created." + echo "The next version number would be: ${NEXT_VERSION}" + git tickets | grep -Eo '(\w+)-([0-9]+)' +else + # Perform the actual release process + # Capture the output of git-tickets + TICKETS_OUTPUT=$(git tickets --update) + + # Use grep to filter the output + TICKET_IDS=$(echo "$TICKETS_OUTPUT" | grep -Eo '(\w+)-([0-9]+)') + + # Prepend the tickets to the CHANGELOG.md + prepend_to_changelog "$NEXT_VERSION" "$TICKET_IDS" + + # Checkout a new branch with the pattern release-### + git checkout -b "release-${NEXT_VERSION}" + + # Add the CHANGELOG.md to the staging area + git add CHANGELOG.md + + echo "Tickets to be included in this release:" + echo "$TICKET_IDS" +fi diff --git a/bin/git-tickets b/bin/git-tickets new file mode 100755 index 0000000..efddc6b --- /dev/null +++ b/bin/git-tickets @@ -0,0 +1,75 @@ +#!/bin/bash +# Prompt for a branch name with a default +prompt_for_branch() { + read -rp "Enter the name of the $1 branch (default: $2): " branch + echo "${branch:-$2}" # Return the entered branch name or the default if none was entered +} + +# Check for --update flag +UPDATE_BRANCHES=false +for arg in "$@"; do + if [ "$arg" == "--update" ]; then + UPDATE_BRANCHES=true + break + fi +done + +# Prompt for the first branch name if not provided +if [ -z "$1" ] || [ "$1" == "--update" ]; then + BRANCH1=$(prompt_for_branch "first" "master") +else + BRANCH1="$1" +fi + +# Prompt for the second branch name if not provided +if [ -z "$2" ] || [ "$2" == "--update" ]; then + BRANCH2=$(prompt_for_branch "second" "staging") +else + BRANCH2="$2" +fi +# Function to update or create temporary branches +process_branch() { + local branch_name=$1 + local temp_branch="temp_${branch_name}_$$" + if $UPDATE_BRANCHES; then + git checkout "$branch_name" &> /dev/null + if ! git checkout "$branch_name" &> /dev/null; then + echo "Failed to checkout branch $branch_name" >&2 + exit 1 + fi + git pull origin "$branch_name" &> /dev/null + echo "$branch_name" + else + git fetch origin "$branch_name":"$temp_branch" &> /dev/null + if ! git rev-parse --verify "$temp_branch" &> /dev/null; then + echo "Failed to fetch and create temp branch for $branch_name" >&2 + exit 1 + fi + echo "$temp_branch" + fi +} + + +# Process the first branch +BRANCH1=$(process_branch "$BRANCH1") + +# Process the second branch +BRANCH2=$(process_branch "$BRANCH2") + +# If not updating branches, use the temporary branches for log +if ! $UPDATE_BRANCHES; then + # Run the git log command and process the output on temporary branches + git log "$BRANCH2".."$BRANCH1" --oneline --no-merges | grep -Eio "(\w+)-([0-9]+)" | tr '[:lower:]' '[:upper:]' | sort -u + + # Delete the temporary branches + git branch -D "$BRANCH1" &> /dev/null + git branch -D "$BRANCH2" &> /dev/null + git status; +else + # Run the git log command and process the output on updated branches + git log "$BRANCH2".."$BRANCH1" --oneline --no-merges | grep -Eio "(\w+)-([0-9]+)" | tr '[:lower:]' '[:upper:]' | sort -u + + # Checkout to the first branch (assumed to be 'master') + git checkout "$BRANCH1" &> /dev/null + git status +fi