Swiftlint: Swiftlint as pre-commit git hook

Created on 29 Aug 2016  路  9Comments  路  Source: realm/SwiftLint

Hi!
I've been using Swiftlint (I'm relatively new to both Swift and Swiftlint) and was trying to implement the lint check as part of pre-commit git hook. I wish to run this only on modified files. When I run standalone script to do the same, I am able to lint on the modified files (expected result) but when I invoke the script as part of pre-commit hook and try to commit files using source tree, Swiftlint runs on the entire git repo.
Could you tell what am I doing wrong?
Thanks!!

question

Most helpful comment

Hi Norio!

Here's the script that I'm using -

#!/bin/bash

#Path to swiftlint
SWIFT_LINT=/usr/local/bin/swiftlint

#if $SWIFT_LINT >/dev/null 2>&1; then
if [[ -e "${SWIFT_LINT}" ]]; then
    count=0
    for file_path in $(git ls-files -m --exclude-from=.gitignore | grep ".swift$"); do
        export SCRIPT_INPUT_FILE_$count=$file_path
        count=$((count + 1))
    done

##### Check for modified files in unstaged/Staged area #####
    for file_path in $(git diff --name-only --cached | grep ".swift$"); do
        export SCRIPT_INPUT_FILE_$count=$file_path
        count=$((count + 1))
    done

##### Make the count avilable as global variable #####
    export SCRIPT_INPUT_FILE_COUNT=$count

    echo "${SCRIPT_INPUT_FILE_COUNT}"

##### Lint files or exit if no files found for lintint #####
    if [ "$count" -ne 0 ]; then
        echo "Found lintable files! Linting..."
        $SWIFT_LINT lint --use-script-input-files --config swiftlint_rules.yml #--reporter json
    else
        echo "No files to lint!"
        exit 0
    fi

    RESULT=$?

    if [ $RESULT -eq 0 ]; then
        echo ""
        echo "Violation found of the type WARNING! Consider fixing them before commit!"
    else
        echo ""
        echo "Violation found of the type ERROR! Must fix before commit!"
    fi
    exit $RESULT

else
    echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

When I run this as a standalone script or while attached with XCode as Run Script Build Phase, it works as expected by linting modified/staged files. However, when run as a pre-commit Git Hook and using Source tree to commit it runs on the entire set of project files.

What I intend to do is to have a Pre-Commit Git Hook in place so developers can't check in files with warnings or errors. Your help is greatly appreciated!

As a guide to my script, I used - https://github.com/realm/SwiftLint/issues/413
Cheers!

edited by norio: add code fencing to script block

All 9 comments

Could you please share your scripts for reproducing the issue on our site?

Hi Norio!

Here's the script that I'm using -

#!/bin/bash

#Path to swiftlint
SWIFT_LINT=/usr/local/bin/swiftlint

#if $SWIFT_LINT >/dev/null 2>&1; then
if [[ -e "${SWIFT_LINT}" ]]; then
    count=0
    for file_path in $(git ls-files -m --exclude-from=.gitignore | grep ".swift$"); do
        export SCRIPT_INPUT_FILE_$count=$file_path
        count=$((count + 1))
    done

##### Check for modified files in unstaged/Staged area #####
    for file_path in $(git diff --name-only --cached | grep ".swift$"); do
        export SCRIPT_INPUT_FILE_$count=$file_path
        count=$((count + 1))
    done

##### Make the count avilable as global variable #####
    export SCRIPT_INPUT_FILE_COUNT=$count

    echo "${SCRIPT_INPUT_FILE_COUNT}"

##### Lint files or exit if no files found for lintint #####
    if [ "$count" -ne 0 ]; then
        echo "Found lintable files! Linting..."
        $SWIFT_LINT lint --use-script-input-files --config swiftlint_rules.yml #--reporter json
    else
        echo "No files to lint!"
        exit 0
    fi

    RESULT=$?

    if [ $RESULT -eq 0 ]; then
        echo ""
        echo "Violation found of the type WARNING! Consider fixing them before commit!"
    else
        echo ""
        echo "Violation found of the type ERROR! Must fix before commit!"
    fi
    exit $RESULT

else
    echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

When I run this as a standalone script or while attached with XCode as Run Script Build Phase, it works as expected by linting modified/staged files. However, when run as a pre-commit Git Hook and using Source tree to commit it runs on the entire set of project files.

What I intend to do is to have a Pre-Commit Git Hook in place so developers can't check in files with warnings or errors. Your help is greatly appreciated!

As a guide to my script, I used - https://github.com/realm/SwiftLint/issues/413
Cheers!

edited by norio: add code fencing to script block

I tested your script with modification using .swiftlint.yml and it worked in SwiftLint repository.

git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree commit -q -F /var/folders/kt/2mwy9b_56_7993x190pl_1fh0000gn/T/SourceTreeTemp.LW7gjW 
1
Found lintable files! Linting...
Loading configuration from '.swiftlint.yml'
Linting 'AutoCorrectCommand.swift' (1/1)
/Users/norio/github/SwiftLint/Source/swiftlint/Commands/AutoCorrectCommand.swift:9:1: error: Variable Name Violation: Variable name should be between 3 and 40 characters long: 'a' (variable_name)
Done linting! Found 1 violation, 1 serious in 1 file.

Violation found of the type ERROR! Must fix before commit!
Completed with errors, see above

Is the issue caused by your configuration file?

@tommyvercetti76 Sorry this is not related to the question at hand, but reading through your script has me a bit puzzled. I could just be missing an obvious bashism here..

This part of your script:

    if [ $RESULT -eq 0 ]; then
        echo ""
        echo "Violation found of the type WARNING! Consider fixing them before commit!"
    else

You are printing the message "Violation found of the type WARNING!..." when the status code is 0 (and printing the error message when it's non-0 as expected). Wouldn't this mean that you always print "Violation found of the type WARNING!...", even if there are no warnings? Swiftlint, from what I can tell, only returns a non-zero status code when there are errors, so I don't see how you are differentiating between warning and success.

@norio-nomura
The script does work as expected when used stand alone (via git command line). But when I used this as a part of Git-Hook and tried to commit a file using 'sourcetree', it lints all the 996 files as opposed to one. When this is integrated with XCode, script works as expected. And this is what has got me confused. I'm using Sourcetree GUI.
To create a hook, I have this script as pre-commit. I've also sym linked it with local .git/hooks.
Not sure if I'm missing anything.

@cfilipov
Yes, I've fixed that now. I was trying to see what sort of error codes are we getting for warning/error. I initially thought Warning will have code 1 and error would have code 2.
Thanks though! :)

Just an update -
I moved the script file and config file at the root of my Git Repo.
When the files in question are not in staged area, the script works as expected. As soon as I move file to staging area, I get "No Lintable file at path ' ' "

I tested with pre-commit as symbolic links and it also worked.
Both of staged and unstated files are linted by same pre-commit script on https://github.com/realm/SwiftLint/issues/785#issuecomment-243940354.

I guess git diff --name-only --cached or git ls-files -m --exclude-from=.gitignore are not working expectedly on your site.
I'm using git version 2.9.3.

Closing due to lack of activity.

@tommyvercetti76 thanks for your script, I've made some changes and it works great

See https://gist.github.com/teameh/effb59ba42c101752e3a59c25a85d941 for the full script

Was this page helpful?
0 / 5 - 0 ratings

Related issues

larslockefeer picture larslockefeer  路  3Comments

jszumski picture jszumski  路  3Comments

mildm8nnered picture mildm8nnered  路  3Comments

Tableau-David-Potter picture Tableau-David-Potter  路  3Comments

muzamilhassan1987 picture muzamilhassan1987  路  3Comments