Golang — Automate Formatting and Linting via Pre-Commit

Increasing developer experience with pre-commits

Itchimonji
CP Massive Programming
5 min readJul 22, 2023

--

Sometimes it is very hard to get all commands in mind how to format and lint our Golang code to increase our developer experience in the team. Especially, when we try to optimize our CI/CD environments to be alerted to code anomalies at an early stage.

Go tools help us to enforce a standard format and ensure that our code is idiomatic and of high quality.

Formatting

To reformat our code to match a standard format automatically, there is a simple command called go fmt in the Golang development tools. It fixes up whitespace for indentation, linting up the fields in a struct, formats basic strings, values, inputs and outputs and many more.

go fmt ./...

To clean up our import statements, there is another Go package called goimports. It adds missing Go import lines or removes unreferenced ones, puts them in alphabetical order, and attempts to guess any unspecified imports. goimports can be used as a replacement for go fmt, because it also formats our code.

go install golang.org/x/tools/cmd/goimports@latest

goimports -l -w

Linting

To ensure our Golang code follows style guidelines or coding conventions, we can use a linter called golint. The tool suggests things like naming variables, formatting error messages and placing comments on public methods or types.

go install golang.org/x/lint/golint@latest 

golint ./...

To run mutliple tools inside one linter, we can use golangci-lint. It combines golint, go vet, and other code-quality tools. It runs all these tools in parallel and uses caching.

go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.53.3

golangci-lint run

Setup a pre-commit

With husky there is a solution to setup pre-commit constructs dependent on our programming environment. Git alone, however, still offers the possibility of being independent of any programming environment with its githooks.

To change the path of the global hook in a local development repository, we need to run the following code.

mkdir ./.githooks
chmod ug+x ./.githooks/*
git config core.hooksPath ./.githooks

Inside the .githooks folder, we need to create a pre-commit file.

touch ./.githooks/pre-commit
chmod ug+x ./.githooks/*

Add the following code to the pre-commit file to add Go commands for formatting and linting.

#!/usr/bin/env bash

go fmt ./...
goimports -l -w . # includes go fmt
golint ./...
go vet ./...
golangci-lint run # includes golint, go vet

Every time we commit Golang code now, the formatter and linter doing their work.

When we check in the .githooks folder, we share this experience with your team members and they can use this automatism, too.

We can also add a script to set the rights for this folder.

touch install-git-hook.sh

Now, we need to add the following code.

chmod ug+x ./.githooks/*
git config core.hooksPath ./.githooks

After this, we can set the permissions via the following command.

bash install-git-hook.sh

Bonus: Add versioning to a pre-commit hook

Sometimes it could be very hard to have a solid git flow regarding handle versions that should be automatically deployed in specific environments like, for example, Kubernetes.

With Git Tags we always have a manual step to set a specific version, that can be used by a CI/CD pipeline. With pre-commit hooks, we can set up versioning automatically.

First of all, we need a unique reference to a version. For this purpose, a local file is suitable, which contains the version according to the semantic-versioning principle. We want to increase the version with every commit. So, as not to violate the principle of semantic versioning, we specify an additional number that reflects the number of commits.

  1. MAJOR version when we make incompatible API changes
  2. MINOR version when we add functionality in a backward-compatible manner
  3. PATCH version when we make backward-compatible bug fixes
  4. COMMIT version when we commit some code
touch .properties.version
echo "0.0.0.0" > .properties.version

We need to add some additional code in our pre-commit file to increase the version in the properties.version file automatically.

#!/usr/bin/env bash

go fmt ./...
goimports -l -w .
golint ./...
go vet ./...
golangci-lint run # includes golint, go vet

file=".properties.version"
v=$(cat "$file")
echo "${v%.*}.$((${v##*.}+1))" > $file
git add .properties.version

With every commit, the pre-commit hook gets triggered and increases the version in the file .properties.version.

Now, we can extract this version in any pipeline to build the project, build any Docker container or do something else with this version.

cat .properties.version

Conclusion

Automatisms make our development life very easy. Formatting and linting can also be automated via pre-commit hooks. This allows us as developers to concentrate on the feature development of our products.

Thanks for reading!

Subscribe now to my newsletter to read more about DevOps, Agile & Development Principles, Angular, and other useful stuff.

Want to connect? 🐦 Twitter | 🔗 LinkedIn | 👽 Medium | 📰 Instagram

Happy Coding! :)

Before you go: 👏 Clap for the story | ✍️ Add a comment | ⚓ Follow me

Resources

Learn More

--

--

Itchimonji
CP Massive Programming

Freelancer | Site Reliability Engineer (DevOps) / Kubernetes (CKAD) | Full Stack Software Engineer | https://patrick-eichler.com/links