🌬️ 🍂 Gone with the wind
Published on

Automating the workflow

Authors
  • avatar
    Name
    ディーン・タリサイ
    Twitter
    @prjctimg

NOTE

Repetitive tasks ought not to be redone by hand. ~me

When overwhelmed with the amount of tasks we have to perform, often repeatedly, certain it becomes tedious to do this by hand. Automation, in the context of this article, allows us to reuse commands or procedures with the obvious benefits being time saved and reduced mental overhead, allowing us to focus on the interesting parts of our work and if necessary, multitask our way through.

What should I automate ?

Everything.

We should automate any work that we can because the goal of using a computer is to reduce the amount of work we have to do as humans. A good example of automation is how platforms like GitHub can watch for events on a repository and react to them on your behalf such as when someone opens a new issue or pushes to main.

How do we set ourselves up for this ?

It depends.

The key takeaway is that for whatever tool or environment you're working in, we should have a way to abstract regular and repetitive tasks. The following sub-headings will go over different scenarios showing automation in practice.

Running at intervals with cron

Using the crontab utility, we can write scripts that can be run at specified intervals. I store my scripts for crontab under $HOME/.routines but you may store yours wherever you see fit.

cd "$HOME/.routines"
# Make it executable
sudo chmod +x workspace_backup.sh
# NB - you can use any text editor
vi workspace_backup.sh

Inside of our workspace.sh, we define our script, for most tasks bash is a good choice because it's widely available in most environments.

#! /bin/env bash

# The directory where your Git repositories are located.
WORKSPACE_DIR="$HOME/workspace"

# The directory where the backups will be stored.
# Ensure this directory exists and the script has write permissions.
BACKUP_DIR="/tmp/workspace_backup"

# This will include a timestamp to make each backup unique.
ARCHIVE_NAME="workspace_snapshot-$(date +%Y%m%d_%H%M%S).tar.gz"

# Temporary directory to store individual git bundles before archiving.
TEMP_BUNDLE_DIR="${BACKUP_DIR}/git_bundles"

echo "Starting workspace backup routine for $(date)"
echo "Workspace directory: ${WORKSPACE_DIR}"
echo "Backup destination: ${BACKUP_DIR}"

# Create backup directory if it doesn't exist
mkdir -p "${BACKUP_DIR}" || {
	echo "Error: Could not create backup directory ${BACKUP_DIR}. Exiting."
	exit 1
}

# Create temporary bundle directory
mkdir -p "${TEMP_BUNDLE_DIR}" || {
	echo "Error: Could not create temporary bundle directory ${TEMP_BUNDLE_DIR}. Exiting."
	exit 1
}

# Find all Git repositories and create bundles
find "${WORKSPACE_DIR}" -type d -name ".git" | while read -r GIT_DIR; do
	# Get the parent directory of .git (which is the repository root)
	REPO_PATH=$(dirname "${GIT_DIR}")
	# Extract the repository name for the bundle file
	REPO_NAME=$(basename "${REPO_PATH}")

	# Construct the full path for the bundle file
	BUNDLE_FILE="${TEMP_BUNDLE_DIR}/${REPO_NAME}.bundle"

	echo "Backing up repository: ${REPO_PATH} to ${BUNDLE_FILE}"

	# Change to the repository directory to create the bundle
	(cd "${REPO_PATH}" && git bundle create "${BUNDLE_FILE}" --all) || {
		echo "Warning: Failed to create bundle for ${REPO_PATH}. Skipping."
	}
done

# Check if any bundles were created
if [ -z "$(ls -A "${TEMP_BUNDLE_DIR}")" ]; then
	echo "No Git repositories found or no bundles were created. Exiting."
	rmdir "${TEMP_BUNDLE_DIR}" # Remove empty temp directory
	exit 0
fi

echo "Creating archive: ${BACKUP_DIR}/${ARCHIVE_NAME}"

# Create a compressed tar archive of all bundle files
# -C "${TEMP_BUNDLE_DIR}" changes to the directory before archiving,
# so the archive contains just the bundle files, not the full path.
tar -czf "${BACKUP_DIR}/${ARCHIVE_NAME}" -C "${TEMP_BUNDLE_DIR}" . || {
	echo "Error: Failed to create archive ${ARCHIVE_NAME}. Exiting."
	rm -rf "${TEMP_BUNDLE_DIR}" # Clean up even on error
	exit 1
}

echo "Backup successful! Archive saved to: ${BACKUP_DIR}/${ARCHIVE_NAME}"

# Clean up temporary bundle files
echo "Cleaning up temporary bundle directory: ${TEMP_BUNDLE_DIR}"
rm -rfv "${TEMP_BUNDLE_DIR}"

echo "Backup process completed."


After we save our script, we then edit our crontab file:

crontab -e

Our script will now run at regular intervals without our intervention.

Easier version control with git hooks

Git hooks allow us to attach routines to events that occur when we are working with git such as committing and pushing. They're particularly useful if you want to deeply integrate with Git (events).

Here's an example of setting up a pre-push hook, it will run before we push changes to our remote repository. If it exits with an error then git push will be cancelled:


# cd into any direcctory with a git repository
cd workspace/me/.git/hooks
mv pre-push.sample pre-push
sudo chmod +x pre-push

This hook will just run tests:


#! /usr/bin/env sh

bun test

You can see the tests being ran when we run git push:

#o %% e %%# Use workflows for package publishing

Publishing from your development machine is the traditional way to do things. Nowadays, it's wiser to have your code/binaries released or published to registries via a workflow. GitHub Actions are suited for this and the open source community has a lot of them available.

A popular option is release-please which allows you to trigger releases and generate changelogs whenever a new git tag is created. This allows you to keep adding commits until you're ready to merge back to the main/stable branch which will then create the release.

Here's an example of how I use release-please :

If the platform offers a developer API, use it

The fun part of being a developer is that you don't have to interact with software like normal users, the hacking mentality pushes us to try different ways to solve problems.

Let's say you want to be able to post about what you're currently doing on Tumblr without too much context switching, that is, you want to do this task without leaving your current UI. The same could also be said about web browsers in as much as terminals. Just as you can switch tabs and move between different apps in Chrome, you should also be able to replicate that navigational freedom in the terminal.

NOTE

I'm writing a small collection of TUIs for platforms I use regularly to address this. The code is WIP

Create content in advance and automate the publishing

Writing is really hard and I often find that I don't have the motivation to type out a lot of words. Which is why I now prefer to write in short bursts and then refine each post as I go, this habit helps me stay consistent.

The zen posts on this site are actually automated and they publish themselves everyday at 5 AM from simple json file that has each day as a key from 1 to 365. The other posts have a released property that tell the day the post will be published on. A script is run everyday at 7 AM to check if there is any post due to be released, if it is found it's draft YAML property is changed from true to false and then make a release commit that triggers a redeployment of the site. Straight forward stuff.

You can even automate theme toggling in your editor (neovim btw)

If you're in nvim you can use the init.lua file to describe the editor's behavior when it starts . The beauty of this all is the freedom to tweak your environment until it suits your workflow. Here's an example of checking if the current theme matches the time of the day:


-- in your init.lua file

local function swap_theme()
  local hour = tonumber(os.date("%H"))
  local light_theme = "tokyonight-day"
  local dark_theme = "tokyonight"
  local is_day = hour >= 6 and hour < 17

  if is_day then
    vim.cmd.colorscheme(light_theme)
    Snacks.notifier("Lights on 🌄", "info", {
      title = "System",
    })
  else
    vim.cmd.colorscheme(dark_theme)
    Snacks.notifier("Lights out 🎑", "info", {
      title = "System",
    })
  end
end

swap_theme()

-- timer to periodically update theme
vim.fn.timer_start(18000000, function()
  swap_theme()
end, { ["repeat"] = -1 })


What now ?

This was just an overview of some of the things that can be automated or, at least some ways to use automation in your development workflow.

You can find Gist with the code samples here , feel free to leave a comment on it and or suggest improvements.