Encoding knowledge with automation scripts
Programming
Encoding knowledge with automation scripts
In the previous post I shared a couple small scripts I use with Git. I automate a lot of the repetition in my development workflow to make tasks not just easier but also more reliable. Automation encodes knowledge. Scripts give me a place to capture things I learn.<br>Below are descriptions of several scripts I use on a daily basis.<br>Most of my scripts aren't portable. They're tailored to the specific tools I use, such as Tmux and Alfred, they often require particular libraries and environment variables, and while some are Bash, most of them favor Clojure (Babashka). Rather than sharing the scripts themselves, this post focuses on the problems that prompted them and what I automated.<br>ws & friends<br>I use Git worktrees extensively, checking out work-in-progress branches and code to review in separate folders and Tmux sessions. Here's one version of the script. My current iteration is called ws and takes two or three parameters:<br>ws []<br>type can be feat, fix, task, or cve. name is the name to use for the branch and Tmux session. If there's a Jira ticket associated with the work, ticket-number captures that.<br>ws creates a new Git branch using the given information (e.g. feature/some-branch-name-TICKET-5555), then checks out the branch in a new Git worktree and creates a Tmux session for it. It also captures the data in a couple of files local to the worktree. One is a local draft of the PR, which is Markdown but has YAML frontmatter where I specify the title of the PR, any labels, reviewers, and the ticket number. Those will be used when creating the PR (see gh-open below). Some of that information is also captured in a .workspace.yaml file, which can be used to re-launch the the Tmux session. Both .workspace.yaml and the PR file are created by ws and ignored by Git via a global gitignore.<br>ws creates the workspace files, but opening the workspace is performed by wso ("workspace open"), which ws invokes but which I can also invoke manually on any directory with a .workspace.yaml file. Initializing the workspace is done by wsi ("workspace initialize"), which sends the init command (see below) to the first Tmux pane in the workspace.<br>Similar to ws is wsc ("workspace checkout"), useful for branches that exist but for which I don't have a local worktree.<br>To review someone else's pull request locally, I use wsr ("workspace review"). It pulls the URL for the PR from the clipboard, fetches the PR from GitHub's API, switches to the local directory for that repo, then invokes wsc for the PR's branch.<br>When I'm done with a workspace, I run wsd ("workspace destroy") to check for pending changes, and if there aren't any, the script switches the Tmux client to a Tmux session that won't be deleted, deletes the Git worktree, and kills the workspace's Tmux session.<br>init and friends<br>I have an init- script for each repo I work in. They do all the setup for a new worktree, such as creating a Python virtual env, activating it, and installing dependencies. Most repos have a Makefile or install.sh script which does the heavy-lifting, so these init-* scripts capture what's specific to my workflow, such as using pyenv rather than some other virtual environment tool.<br>init is just a wrapper script that 1) inspects the Git repo to figure out which init-* script to run, 2) verifies the init-* exists, and 3) runs it. ws launches this automatically in new workspaces, but on occasion I invoke it manually.<br>cve<br>A few weeks ago I addressed a lengthy backlog of security vulnerabilities. I chose to tackle them in bulk—rather than chip away here and there—so I could focus on developing a system and encoding it in a script, smoothing the process for future fixes. The result was the script cve with several subcommands.<br>cve check reads the system clipboard to get the URL for a Jira ticket, parses the ticket's description, finds the name of the affected Docker image and the package that needs to be upgraded, then opens a URL to our internal artifact repository that lists the image's current vulnerabilities. Occasionally vulnerabilities have been fixed by other changes and the ticket remains open. When that happens, cve close will comment on the Jira ticket with a link to the vulnerabilities page, assign it to me, and close the ticket. If the vulnerability still exists, cve ws finds the repo that produces the affected Docker image and invokes ws cve with the CVE's ID.<br>cve repro builds the Docker image, then runs docker scout cves and picks out the sections mentioning the CVE's identifier. This is the most complicated subcommand. Some of the Dockerfiles need tweaks to build locally (for which I keep a set of patches), several of the images depend on other images having been built first, some images are built by specific Makefiles, and building can require particular environment variables. All that information is tracked in a data structure in the script.<br>cve...