Posts tagged with “bash”

A bash script `ci` to help you write commit message and commit with OPEN AI/Groq API

Writing commit message could be time-consuming if you want a good summrize. ChatGPT just released their cheapest but still powerful model gpt-4o-mini, we can use it to save our time and keep the commit message accurate.

You need to put your API KEY in environment variable OPENAI_API_KEY before running this script. You need to run git add first before running this ci script. If you don't want to bother adding first, change git diff --cached -w -b to git diff -w -b and add -a option in the commit command (the last line of the script)

#!/bin/bash

# Get git changes
changes=$(git diff --cached -w -b)

# Exit if no changes
if [ -z "$changes" ]; then
  echo "No changes to commit."
  exit 0
fi

# Set prompt template
prompt_template=$(cat <<-END
You are good at writing git commit messages;
You follow the conventional commits specification:

feat: for new features
chore: for maintenance work
fix: for bug fixes

Please help write a commit message for the following changes from a `git diff` command.
Please try to summerize all meaningful changes while keep the result short.
THE RESULT SHOULD ONLY BE NO MORE THEN 100 CHARACTERS.

please do not respond any other information/text rather than the commit message itself.
and here're the changes:

END
)

prompt_template+="$changes"

# Build JSON request body using jq
request_body=$(jq -n --arg model "gpt-4o-mini-2024-07-18" --arg prompt "$prompt_template" \
  '{model: $model, messages: [{role:"system",content:"You are a programmer"},{role: "user", content: $prompt}], max_tokens: 32768, seed: 45, temperature: 0}')

# Use curl to request the OpenAI API to generate a commit message
response=$(curl -s --request POST \
  --url https://api.openai.com/v1/chat/completions \
  --header "Authorization: Bearer $OPENAI_API_KEY" \
  --header "Content-Type: application/json" \
  --data "$request_body")

# Extract commit message from the response
commit_message=$(echo "$response" | jq -r '.choices[0].message.content')

# Exit if the commit message is empty
if [ -z "$commit_message" ]; then
  echo 'failed to generate a commit message'
  exit 1
fi

# Commit changes
git commit -m "$commit_message"

2024-07-24 update

Free alternative provided by Groq

If you don't want to pay for the ChatGPT API, you can opt for the free alternative provided by Groq. To get started, simply sign up for a Groq account using Google Login. Once you've created your account, you can generate an API key by following this link: https://console.groq.com/keys. Finally, make a minor modification to your script, as outlined below.

# Build JSON request body using jq
#request_body=$(jq -n --arg model "gpt-4o-mini-2024-07-18" --arg prompt "$prompt_template" \
#  '{model: $model, messages: [{role:"system",content:"You are a programmer"},{role: "user", content: $prompt}], max_tokens: 50, seed: 45, temperature: 0}')
#response=$(curl -s --request POST \
#  --url https://api.openai.com/v1/chat/completions \
#  --header "Authorization: Bearer $OPENAI_API_KEY" \
#  --header "Content-Type: application/json" \
#  --data "$request_body")

request_body=$(jq -n --arg model "mixtral-8x7b-32768" --arg prompt "$prompt_template" \
  '{model: $model, messages: [{role:"system",content:"You are a programmer"},{role: "user", content: $prompt}], max_tokens: 32768, stream: false, temperature: 0, top_p: 1, stop: null}')

# Use curl to request the OpenAI API to generate a commit message
response=$(curl -s --request POST \
  --url https://api.groq.com/openai/v1/chat/completions \
  --header "Authorization: Bearer $GROQ_API_KEY" \
  --header "Content-Type: application/json" \
  --data "$request_body")

A tip to ease the process creating new feature branch

We use feature/ticket-number-team-abbr as feature branch name, such as feature/mt-1234-axo at work.

If you mainly work with a huge repository. Everytime, you switch to the integration/main branch and run git pull before you create a feature branch, it would take a while as it needs to update your work directory and normally there are a lot of files changed.

I use a different way which is a little bit speedy. Whatever which branch you are now in, run

git fetch && git checkout -b feature/mt-xxxx-axo origin/integration 

It helps but I still need to type the above, which is still a lot of letters! So, I create a bash script to help me more,

see the following command nbi 38546

nbi 38546
remote: Enumerating objects: 22, done.
remote: Counting objects: 100% (22/22), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 22 (delta 17), reused 22 (delta 17), pack-reused 0
Unpacking objects: 100% (22/22), 4.43 KiB | 5.00 KiB/s, done.
From github.com:Euronet-XE/DFX
   941796a8a..11f76bff7  feature/mt-38183-fugu -> origin/feature/mt-38183-fugu
 * [new branch]          feature/mt-39492-ice  -> origin/feature/mt-39492-ice
 * [new branch]          feature/mt-39744-ice-card -> origin/feature/mt-39744-ice-card
branch 'feature/mt-38546-axo' set up to track 'origin/integration'.
David.Wei @ /d/git/xemt-core/dfx - [feature/mt-38546-axo] $

what’s in this nbi script? here it is

cat ~/bin/nbi
#!/bin/bash

# Check if the current directory is a git repository
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
    echo "Error: Current directory is not a git repository."
    exit 1
fi

# Run git fetch to get the latest changes from the remote repository
git fetch

# Determine the action based on the script name
case "$(basename "$0")" in
    nbi)
        # Check if an argument is provided
        if [[ $# -eq 1 ]]; then
            # Run git checkout to create and switch to a new branch based on the integration branch
            git checkout -b "feature/mt-$1-axo" "origin/integration"
            exit $?
        else
            echo "Usage: $0 <anumber>"
            exit 1
        fi
        ;;
    nbm)
        # Check if an argument is provided
        if [[ $# -eq 1 ]]; then
            # Run git checkout to create and switch to a new branch based on the main branch
            git checkout -b "feature/mt-$1-axo" "origin/main"
            exit $?
        else
            echo "Usage: $0 <anumber>"
            exit 1
        fi
        ;;
    *)
        echo "Error: Unsupported script name."
        exit 1
        ;;
esac

why do I call it nbi ? haha, it is a ABBR from new branch from integration

Wait, why did I mention nbm in the script? Yes, you can copy this nbi script with name nbm , then using the nbm command it will work the same way with the repositories that use main as the integration branch.

Did you see? How lazy I am!

2024-07-22 Update: I also wrote another script sw to ease the switching branches operation:

#!/bin/bash

# Check if the user provided a number
if [ -z "$1" ]; then
  echo "Usage: sw <number>"
  exit 1
fi

# Construct the branch name
branch_name="feature/mt-$1-axo"

# Switch to the branch
git switch "$branch_name"

# Check if the switch was successful
if [ $? -eq 0 ]; then
  echo "Switched to branch '$branch_name'"
else
  echo "Failed to switch to branch '$branch_name'"
fi

How to delete all bin/obj folders in a complex solution in GitBash

Sometimes we need to delete all the bin/obj folders in a solution to resolve issues in Rider or Visual Studio. I assume you already have your preferred method for this task, but I would like to share my approach here in case someone else is unaware of how to do it in GitBash or MSYS terminal:

#!/bin/bash

set -e

# Find and display directories to be deleted
find . \( -iname "bin" -o -iname "obj" \) -type d -print

# Prompt user for confirmation
read -p "The above folders are going to be deleted, are you sure? [Y/N]: " -n 1 -r
echo    # Move to a new line

# Delete directories if confirmed
if [[ $REPLY =~ ^[Yy]$ ]]; then
    find . \( -iname "bin" -o -iname "obj" \) -type d -exec rm -rfv {} +
    echo "Done"
else
    echo "No"
    exit 1
fi

Don't simple unset them afterward when using `shopt` change a setting

Sometimes we need to run shopt -s dotglob nullglob before moving files including dotfiles. So there's another question, do we need to set it back afterward? The most correct answer is

It's usually not clear if either dotglob or nullglob were already set before running shopt -s to set them. Thus, blindly un-setting them may not be the proper reset to do. Setting them in a subshell would leave the current shell's settings unchanged:

( shopt -s dotglob nullglob; mv ~/public/* ~/public_html/ )

Reference: Jeff Schaller's answer under this question

switch case in bash script

, change the first letter of the value of the variable to lowercase, ,, change the value of the whole variable to lower case.

$ test='HELLO'
$ echo $test
HELLO
$ echo ${test,}
hELLO
$ echo ${test,,}
hello
$ test=${test,,}
$ echo ${test^}
Hello
$ echo ${test^^}
HELLO