Creating a Post-commit hook with Swiftlint Autocorrect.

Have you ever wondered if you could launch a git hook that triggers a certain script that could help you do some task? Me too! Well, not really, until I actually needed it :D
In my case, I work with Xcode (iOS dev here, indeed) and among us iOS developers, it’s a well known fact that Xcode doesn’t provide an IDE with autocorrect functionality, like others do. We do use a tool called “SwiftLint” which triggers a lint in our project to enforce Swift style and conventions. And it also provides a “Autocorrect” command.
Problem is that I wanted to autocorrect automatically, without me needing to run SwiftLint autocorrect everytime in terminal, since I tend to end up forgetting to do this kind of task manually.
When you’re working on a big project with multiple devs at the same time, you need to somehow improve at least how autocorrect is triggered. I started learning about git hooks, and they seem very handy to do this kind of work. Which led me to think about steps on what I wanted and how could I achieve it:
- Run SwiftLint autocorrect only in staged files, so I wouldn’t add more warnings to the project.
- Since we use danger to pinpoint this missing lints in our PR’s, I wanted to skip this behaviour because it added a lot of noise, and since we are humans, we’ll get used to the warnings and end up not fixing it.
Both of the steps above led into this final idea:
When editing or creating files, run SwiftLint autocorrect after a git commit is made over these files.
So I ended creating the following files:
1.- The bootstrap file which will copy the hook file inside .git/hooks/pre-commit path. I’ve called this file “bootstrap_hook.sh”
#!/usr/bin/env bash
# Usage: scripts/autocorrectset -eu
echo "Configuring pre-commit hook..."
file="../.git/hooks/pre-commit"
echo $(pwd)
rm -f $file
cp -f pre-commit $file
echo "Done coping pre-hook in $file"
2. And the code that will evaluate the files that are only in staging mode, so after you do a commit, these files will be autocorrected. If there’s anything to correct, then a new commit will be shown with these changes.
#!/bin/bash
echo "post-commit started"
# Run SwiftLint
START_DATE=$(date +"%s")SWIFT_LINT=/usr/local/bin/swiftlint# Run SwiftLint for given filename
run_swiftlint() {
local filename="${1}"
echo "File is: ${filename}"
echo "File with previous extension is: ${filename#*.}"
if [[ "${filename##*.}" == "swift" ]]; then
if [[ "${filename#*.}" != "generated.swift" ]]; then
echo "Autocorrecting..."
${SWIFT_LINT} autocorrect --path "${filename}"
${SWIFT_LINT} lint --path "${filename}"
fi
fi
}if [[ -e "${SWIFT_LINT}" ]]; then
echo "SwiftLint version: $(${SWIFT_LINT} version)"
# Run only if not merging
if ! git rev-parse -q --verify MERGE_HEAD; then
# Run for both staged and unstaged files
echo "Enter merging"
git diff --name-only | while read filename; do run_swiftlint "${filename}"; done
git diff --cached --name-only | while read filename; do run_swiftlint "${filename}"; done
fi
else
echo "${SWIFT_LINT} is not installed. Please install it first from https://www.github.com/realm/SwiftLint"
exit 0
fiEND_DATE=$(date +"%s")DIFF=$(($END_DATE - $START_DATE))
echo "SwiftLint took $(($DIFF / 60)) minutes and $(($DIFF % 60)) seconds to complete."echo "post-commit finished"
Now, to use it, the only thing you have to do is to run the bootstrap file and let git do his magic:
To run it:
$ sh bootstrap_hook.sh
I have copied these files in my github account if you want to clone it, fork it or pull request it :D https://github.com/phynet/Pre-Hook-Swiftlint-Autocorrect