What did I do yesterday? This Script Can Help

As a programmer, I often get so focused on solving problems that I forget to prepare for standups. The daily meeting doesn't allow extra time for preparation. If you struggle to remember what you did yesterday, like I did, this short worklog script can help.

The Worklog Script

Save the following script as worklog and put it into your ~/bin or any other bin directory in your PATH environment variable. Don't forget to make it executable with chmod +x worklog.

#!/usr/bin/bash

days=1
if [ "$1" != "" ]; then
  days=$1
fi

echo
echo -n "On project $(git remote -v | head -n1 | awk '{print $2}' | sed -e 's,.*:\(.*/\)\?,,' -e 's/\.git$//')"
echo
echo
git --no-pager log --no-merges --pretty=tformat:"- %ad | %s%C(auto)%d [%h]" --date=short --reverse --all --since=${days}.days.ago --author="$(git config user.name)" 2>&1
echo

How It Works

  1. Default Days Setting:

     days=1
     if [ "$1" != "" ]; then
       days=$1
     fi
    

    This part sets the default number of days to 1. If you provide a different number as an argument when running the script, it updates the days variable accordingly.

  2. Fetching Project Name:

     echo
     echo -n "On project $(git remote -v | head -n1 | awk '{print $2}' | sed -e 's,.*:\(.*/\)\?,,' -e 's/\.git$//')"
     echo
    

    This part retrieves the project name from the Git remote URL and displays it. It uses a combination of git remote -v, awk, and sed commands to extract and format the project name.

  3. Generating the Git Log:

     git --no-pager log --no-merges --pretty=tformat:"- %ad | %s%C(auto)%d [%h]" --date=short --reverse --all --since=${days}.days.ago --author="$(git config user.name)" 2>&1
    

    This part generates the Git log for the specified number of days. It includes:

    • --no-pager: To prevent paging the output.
    • --no-merges: To exclude merge commits.
    • --pretty=tformat: To format each commit log line.
    • --date=short: To display dates in short format.
    • --reverse: To show the oldest commits first.
    • --all: To include all branches.
    • --since=${days}.days.ago: To limit the log to commits from the specified number of days ago.
    • --author="$(git config user.name)": To filter commits by the current Git user.
  4. Outputting the Result:

     echo
    

    Finally, it prints a blank line for better readability of the output.

Running the Script

To see what you have done since 1 day ago, simply run:

worklog

If you want to see the work done in the last 7 days, run:

worklog 7

Handling Multiple Projects

If your work involves multiple projects, the following script can help:

Save the following script as wlog and put it into your ~/bin directory. Don't forget to make it executable with chmod +x wlog.

#!/bin/bash

# Define an array with the project directories
project_dirs=(
    /d/git/xemt-core/dfx
    /d/git/apollo/mock
)

# Loop through each project directory and run the commands
for dir in "${project_dirs[@]}"; do
    (cd $dir && worklog "$@" && cd - >/dev/null)
done

How It Works

  1. Project Directories:

     project_dirs=(
         /d/git/xemt-core/dfx
         /d/git/apollo/mock
     )
    

    Define an array containing the directories of your projects.

  2. Loop Through Projects:

     for dir in "${project_dirs[@]}"; do
         (cd $dir && worklog "$@" && cd - >/dev/null)
     done
    

    Loop through each directory, change to that directory, run the worklog script with any passed arguments, and then change back to the previous directory. The cd - >/dev/null part suppresses output from the directory change.

This script helps me quickly summarize my work for daily standup meetings. Customize the project directories in the wlog script to match your projects and streamline your standup preparation.

[Solution] How to limit Google Chrome Cache Size

Click the title to see the details. By the way, this solution not only works on windows, but also works on Linux platforms: You need to find the correct place on linux platform to add the parameter though.

Using `git diff HEAD` to show All Changes

You probably know:

  • git diff shows unstaged changes.
  • git diff --cached shows staged changes.

But how do you see all changes in one go? Just use:

git diff HEAD

Here's the breakdown:

  • git diff compares the working directory to the staged index. If nothing is staged, it's the same as git diff HEAD.
  • git diff --cached compares the staged index to HEAD. It's a shortcut for git diff --cached HEAD.
  • git diff HEAD (or git diff <commit/branch/tag>) compares your current working directory with the specified commit.

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")

Dart `...` Spread Operator: Simplifying Conditional Widget Addition in Flutter

The Dart ... spread operator is a powerful feature that allows you to insert multiple elements from a collection into another collection. This is particularly useful when building Flutter widget trees, as it can make your code more concise and readable.

What is the Spread Operator ...?

The ... operator is used to expand elements of a collection and add them to another collection. For example:

List<int> list1 = [1, 2, 3];
List<int> list2 = [0, ...list1, 4];
print(list2); // Output: [0, 1, 2, 3, 4]

Using the Spread Operator in Flutter Widgets

In Flutter, you can use the ... operator to conditionally add multiple widgets to a widget list, making the code cleaner and more maintainable.

Without the Spread Operator

If you don't use the ... operator, you might end up writing repetitive conditional checks like this:

AppBar(
  title: const Text('Note Details'),
  actions: [
    if (widget.note.userId == UserSession().id)
      IconButton(
        icon: const Icon(Icons.edit),
        onPressed: _enterEditingMode,
      ),
    if (widget.note.userId == UserSession().id)
      IconButton(
        icon: const Icon(Icons.delete),
        onPressed: () async {
          await DialogService.showConfirmDialog(
            context,
            title: 'Delete note',
            text: 'Each note is a story, are you sure you want to delete it?',
            yesCallback: () => _controller.deleteNote(context, widget.note.id),
          );
        },
      ),
  ],
)

This approach involves duplicating the condition check for each widget, making the code verbose and harder to maintain.

With the Spread Operator

Using the ... spread operator, you can simplify the code by grouping the widgets under a single conditional check:

AppBar(
  title: const Text('Note Details'),
  actions: [
    if (widget.note.userId == UserSession().id) ...[
      IconButton(
        icon: const Icon(Icons.edit),
        onPressed: _enterEditingMode,
      ),
      IconButton(
        icon: const Icon(Icons.delete),
        onPressed: () async {
          await DialogService.showConfirmDialog(
            context,
            title: 'Delete note',
            text: 'Each note is a story, are you sure you want to delete it?',
            yesCallback: () => _controller.deleteNote(context, widget.note.id),
          );
        },
      ),
    ],
  ],
)

This method is more concise and only requires a single condition check, reducing redundancy and improving readability.

Benefits of Using the Spread Operator

  1. Reduces Code Duplication: The spread operator allows you to write less code by removing the need for multiple conditional checks.
  2. Improves Readability and Maintainability: With fewer lines of code and clearer structure, your code is easier to read and maintain.
  3. Simplifies Conditional Addition of Multiple Elements: When you need to add multiple elements based on a condition, the spread operator provides a clean and efficient way to do so.