Wrap logs in codeblocks

13 September, 2023 - Tags: bash, til


Problem Statement

I was working on some builds and was trying to improve the security posture of the Dockerfile and overall build process. As it always happens, some of the builds were failing and I wanted to share the logs via GitHub gist. One way is that you directly use your mouse and keep copy and pasting stuff to a gist via a UI or put that in codeblock and then share it but that's not feasible if you're doing a lot of builds and testing it out say every 2-3 minutes.

I wanted a solution that will automate the process.

The obvious and the first method where I looked is to write all the stdout and stderr logs messages to a file when we invoke a docker build for a Dockerfile. I used |& bash operator for this purpose. This basically writes everything to a file when executed.

To summarize, the build command looked like this.

bash

$ docker build -t ttl.sh/$(uuidgen | cut -d - -f 1):1h -f Dockerfile . |& tee docker_build_logs.md

fish

docker build -t ttl.sh/(uuidgen | cut -d - -f 1):1h -f demo/Dockerfile . &| tee docker_build.md

Note: There are some very minor differences here, we don't use $ in fish when it comes to command expansion and we use &| in fish for redirection.

Wrapping Logs inside Markdown codeblock

If you look at the logs then it looks something like this.

#1 [internal] load .dockerignore
#1 transferring context: 2B done
#1 DONE 0.0s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 191B done
#2 DONE 0.0s

#3 [internal] load metadata for docker.io/library/openjdk:17-alpine
#3 DONE 0.5s

#4 [internal] load build context
#4 transferring context: 2B done
#4 DONE 0.0s

It's good but not markdown compatible, if you'll upload it directly to GitHub gist then you'll not have a smooth experience looking at it.

I wanted to wrap these logs in markdown codeblock so that it looks good and GitHub gist and I can also use gh gist create command and after that I can automate it using a script.

So, I wanted the file to start with ```bash and end with ````:

wraping a single file inside codeblock

After few iterations I came up with this script below:

#!/bin/bash

file="$1"

sed -i '1i```bash' $file
printf '\n```' >> $file

wraping multiple files inside codeblock

This was working well but I also wanted to have the ability to simultaneously add codeblocks to a lot of files. So, again after a few iterations I came up with this.

#!/bin/bash

files=("$@")

for file in "${files[@]}"
do
  sed -i '1i```bash' "$file" 
  printf '\n```\n' >> "$file"
done

Now, this was also working good.

removing codeblocks

Now, I wanted to remove those codeblocks from the existing file to which I have already added the codeblock for quick testing. I came up with this script after reading the sed manual.

#!/bin/bash

files=("$@")

for file in "${files[@]}"
do
  sed -i '1d;$d' $file
done

I'm thinking of keeping the wrap one as cwrap in the path and unwrap one as unwrap in the path. This will I'll be able to execute the script from anywhere in the system.

Credits: