inkel

Software programmer interested in SRE, DevOps, Machine Learning and Augmented Reality.


How to properly check environment variables values in Go

1min.

One thing I’ve found fairly often in Go programs is people checking if an environment variable is defined by using the os.LookupEnv function, that returns a string with the value, and a boolean indicating that the variable is present. However, what most people seem to miss is the comment that the returned value might still be empty!

Take for instance the following program that you can try in the Go Playground:

package main

import (
	"fmt"
	"os"
)

func main() {
	os.Setenv("FOO", "bar")
	printEnv("FOO")

	os.Setenv("FOO", "")
	printEnv("FOO")

	os.Unsetenv("FOO")
	printEnv("FOO")

}

func printEnv(v string) {
	ge := os.Getenv(v)
	le, ok := os.LookupEnv(v)
	fmt.Printf("Getenv(%[1]q) => %[2]q\nLookupEnv(%[1]q) => (%[3]q, %[4]t)\n\n", v, ge, le, ok)
}

If you run this, the results might not be what you were expecting:

Getenv("FOO") => "bar"
LookupEnv("FOO") => ("bar", true)

Getenv("FOO") => ""
LookupEnv("FOO") => ("", true)

Getenv("FOO") => ""
LookupEnv("FOO") => ("", false)

Now you know: the proper way to check an environment variable os it use os.LookupEnv and check both the boolean and that the string isn’t empty, otherwise you might introduce a bug in your program.

PS: how cool is that you can refer to arguments in a formatting string using their position?


Replace Go module with local version

1min.

I was going to write about this, but Pam Selle already did it: Use a Local Version of a Library in Go.

Long story short: just run go mod edit -replace path/to/module=/absolute/local/path and you’re good to go! Now when you compile your Go project it will be using the changes in your local environment and not those published in Go module registry.


Change several Git commits' author easily

4min.

Recently I’ve changed jobs, and that meant, among many other things, that my work email address changed, which means that my commits are now using the wrong email address! I need to fix that, but of course I’ve already committed stuff using my old email address. How can I fix that?

Luckily the solution isn’t difficult, though it took me a while to properly figure it out.

The first thing I needed to do was to configure my repository to use my work email address:

path/to/work-repo $ git config user.name "Leandro López (inkel)"
path/to/work-repo $ git config user.email "work@example.com"

Note that I’m doing this only for my work related repositories, so all of my other work (e.g. public or open source) uses my personal email address.

Next I want to know which commits SHA1s are using my personal email address. I can use the --author flag of git-log(1) and get that information easily:

$ git log --pretty=format:"%h - %aN <%ae> - %s" --abbrev-commit --author=personal@example.com
86b860dcc - inkel <personal@example.com> - Use stringSet for collecting child modules
9822062a9 - inkel <personal@example.com> - Use stringSet for collecting top root modules
d6d397f3c - inkel <personal@example.com> - Add stringSet type to collect unique set of strings

Now what I want to do is to reset the author to use the one I configured for this repository without editing the commit message; additionally I want to add a Signed off by line at the end of each commit message. One way to do this is to manually execute the following for every commit:

$ git commit --amend --signoff --author="Leandro López (inkel) <work@example.com>" $COMMITSHA

But as you can figure out, this becomes tedious if you have multiple commits. So let’s use the power of git-rebase(1) and automate this:

$ git rebase --exec='git commit --no-edit --amend -s --reset-author' d6d397f3c^
Executing: git commit --no-edit --amend -s --reset-author
[detached HEAD f29b70ad2] Add stringSet type to collect unique set of strings
 2 files changed, 120 insertions(+)
 create mode 100644 docker/terraform/automation/stringset.go
 create mode 100644 docker/terraform/automation/stringset_test.go
Executing: git commit --no-edit --amend -s --reset-author
[detached HEAD 3ca17042b] Use stringSet for collecting root modules
 1 file changed, 7 insertions(+), 21 deletions(-)
Executing: git commit --no-edit --amend -s --reset-author
[detached HEAD 5d168a566] Use stringSet to collect modules
 1 file changed, 3 insertions(+), 14 deletions(-)
Successfully rebased and updated refs/heads/foo.

And that’s it! All the commits got fixed to use my work email address instead.

What is going on?! Let’s dig into it

First is the --exec flag. This tells Git that for the given list of commits it needs to execute that command after each commit. In this case the command to execute is git commit --no-edit --amend -s --reset-author which amends the commit (--amend) without changing the commit message (--no-edit) except by adding a Signed off by line at the end of the message (-s which is short for --signoff) and changing the author to the one this repository should use (--reset-author, remember we add a custom configuration for it).

Then comes the commit list, in this case d6d397f3c^. Look again at the list of commits above. If you see, the SHA is the same as the one at the bottom of the list, which is the first commit of the list (they are shown in reverse order). The ^ at the end of the SHA instructs Git to go through the current list of commits until the parent of that commit, without including it.

And that’s it! Once this is done, I pull the list of commits again and it looks right:

$ git log --pretty=format:"%h - %aN <%ae> - %s (%cr)' --abbrev-commit --date=relative" --author=work@example.com
5d168a566 - Leandro López (inkel) <work@example.com> - Use stringSet for collecting child modules
3ca17042b - Leandro López (inkel) <work@example.com> - Use stringSet for collecting top root modules
f29b70ad2 - Leandro López (inkel) <work@example.com> - Add stringSet type to collect unique set of strings

This is a very particular use case, but what else we could do with it? Well, you can pass anything to the exec flag, not only Git commands, so you could say run your test suite for each commit and if the command fails then it will stop executing the rebase, allowing you to fix things before continuing. Definitely a very powerful tool to have in your toolbox!


Hello, Grafana Labs!

2min.

It’s been a while since my last post here, not because I’m lazy (which I am), but because as you know I recently changed jobs. It’s been almost a month at my new place, and now I feel confident to say that I joined Grafana Labs as an SRE for the internal cloud platform!

For most of my career I worked as a backend developer, only dabbling sporadically into an operations role, so I would be lying if I said that impostor syndrome didn’t kick in during my first few days at this new role, but luckily my team is super friendly, helping, and understanding, and my confidence is getting bigger as days pass. I think I made the right decision deciding to jump into this new adventure.

Switching jobs is never easy, specially after almost a decade at my previous work, and thus some of my schedules were affected, like the weekly cadence of newsletter or writing into this blog. I hope to get back into rhythm soon.

This past month I’ve spent it mostly going through the onboarding process, getting to know my team, some other teams' leaders, and familiarizing with the codebase and tools like Grafana, Loki, and Tanka. And I’ve even found the time to add a performance contribution to a third-party library!

There are still lots of things to learn, but for now I’ll continue to learn more about this amazing company and the work I’ll be doing, improving my skills, and learning a few more tricks. The future looks really bright!


Goodbye, Theorem

2min.

Today is my final day at Theorem after almost 10 years. It is a day full of mixed feelings for me, as I’m excited for what’s waiting for me next week (more on that, well, next week) and I’m saddened for leaving this amazing team of friendly and talented human beings.

When I joined the Citrusbyte, how it was named at the time, we were less than 20 people working in a hectic but fun and creative environment. And while it might seem hard to believe, that same spirit is still around all these years later, although luckily is not (that) hectic anymore.

Not only the company grew throughout but so did I. I went from being a single guy who had just bought an apartment doing nothing more than programming and reading all day to a father of two and owner of a house. And this company always had my back because all of us employees are treated like people.

But I digress…

Yesterday I’ve got a farewell Meet call with lots of teammates, and I would be lying if I wouldn’t say that afterwards my ego was the size of a continent, I’m happy and proud of leaving a mark on Citrusbyte/Theorem’s culture, and I will forever be grateful and honoured for this past decade. And who knows, maybe someday I’ll return with new tricks to share.

Me as King inkel at Gargonza Castle, Italy

inkelinks S02E03

1min.

Yesterday episode S02E03 of my newsletter was released. I hope you enjoy it! And help me making it better.


inkelinks S02E02

1min.

I might be on vacation but the second episode of 2021 edition of my newsletter is out. Enjoy and share it with your friends!


inkelinks S02E01

1min.

A new year has begun, and a new issue of my newsletter is out. Check it out!


Enabling Comments

1min.

I’ve been looking for a solution to add comments to this blog, but none of them convinced me, as required adding some JavaScript or IFRAME, which doesn’t feel right, so I decided to try a new approach and I’ve enabled GitHub Discussions in the repository where this blog’s content is hosted. I still have to create an entry for each post, which is a tiresome process as there doesn’t seem to be an API for it yet, and also I haven’t decided if that’s something I’d like to have or have you creating a new discussion if needed.


inkelinks S01E06 - Season Finale

1min.

The last one of the year! This episode is full with interesting links, but the one I like the most is the video at the end. I hope you enjoy it!