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 needed it 😀

In my case, I work with Xcode (iOS dev here, indeed) and it’s well known between us, iOS developers, that Xcode doesn’t provide a IDE with an autocorrect functionality, like others have. We do use a tool called “SwiftLint” wich 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 improve somehow the way at least how autocorrect is triggered. I started learning about git hooks, and they seem very handy to do this kind of work. Ok, so, I started to think about steps on what I wanted and how could I achieve it:

  1. Run swiftlint autocorrect only in staged files, so I wouldn’t add more warnings to the project.
  2. Since we use danger to pint point this missing lints in our PR’s, I wanted to skip this behaviour because it added a lot of noise and as human do, we’ll get used to the warnings and end up not fixing it :shruggs:

Both of the steps above ended up in this final idea:

When editing or creating files, run swiflint autocorrect after a commit is made over these files.

So, I ended creating the next 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/autocorrect

set -eu
echo "Configuring pre-commit hook..."
file="../.git/hooks/pre-commit"
path=".git/hooks"
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
fi

END_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 😀 https://github.com/phynet/Pre-Hook-Swiftlint-Autocorrect

 

Sofia Swidarowicz

I'm an iOS Software Engineer mostly. Known as phynet in the internez. I'm me, full of memory failure and lovely karma.

 

Leave a Reply

Your email address will not be published. Required fields are marked *