diff --git a/.gitignore b/.gitignore index b3124ecb..fb1b67bd 100644 --- a/.gitignore +++ b/.gitignore @@ -110,7 +110,7 @@ venv.bak/ *.i64 !rules/lib -# hooks output +# hooks/ci.sh output isort-output.log black-output.log rule-linter-output.log diff --git a/doc/installation.md b/doc/installation.md index a54525ee..0fad9613 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -68,10 +68,17 @@ To install these development dependencies, run: Note that some development dependencies (including the black code formatter) require Python 3. +To check the code style, formatting and run the tests you can run the script `scripts/ci.sh`. +You can run it with the argument `no_tests` to skip the tests and only run the code style and formatting: `scripts/ci.sh no_tests` + ### 3. Setup hooks [optional] If you plan to contribute to capa, you may want to setup the hooks. Run `scripts/setup-hooks.sh` to set the following hooks up: -- The `post-commit` hook runs checks after every `git commit`, letting you know if there are code style or rule linter offenses you need to fix. -- The `pre-push` hook runs various style and lint checks as well as the tests. If they do not succeed `git push` is blocked. +- The `pre-commit` hook runs checks before every `git commit`. + It runs `scripts/ci.sh no_tests` aborting the commit if there are code style or rule linter offenses you need to fix. + You can skip this check by using the `--no-verify` git option. +- The `pre-push` hook runs checks before every `git push`. + It runs `scripts/ci.sh` aborting the push if there are code style or rule linter offenses or if the tests fail. This way you can ensure everything is alright before sending a pull request. + diff --git a/scripts/hooks/pre-push b/scripts/ci.sh similarity index 79% rename from scripts/hooks/pre-push rename to scripts/ci.sh index 51e3830b..f9b0bde1 100755 --- a/scripts/hooks/pre-push +++ b/scripts/ci.sh @@ -1,3 +1,5 @@ +#!/usr/bin/env bash + # Copyright (C) 2020 FireEye, Inc. All Rights Reserved. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -37,7 +39,7 @@ python_3 'isort --profile black --length-sort --line-width 120 -c .' 'isort-outp if [ $? == 0 ]; then echo 'isort succeeded!! 💖'; else - echo 'isort failed 😭'; + echo 'isort FAILED! 😭'; echo 'Check isort-output.log for details'; restore_stashed; exit 1; @@ -48,7 +50,7 @@ python_3 'black -l 120 --check .' 'black-output.log'; if [ $? == 0 ]; then echo 'black succeeded!! 💝'; else - echo 'black failed 😭'; + echo 'black FAILED! 😭'; echo 'Check black-output.log for details'; restore_stashed; exit 2; @@ -59,24 +61,26 @@ python ./scripts/lint.py ./rules/ > rule-linter-output.log 2>&1; if [ $? == 0 ]; then echo 'Rule linter succeeded!! 💘'; else - echo 'Rule linter failed 😭'; + echo 'Rule linter FAILED! 😭'; echo 'Check rule-linter-output.log for details'; restore_stashed; exit 3; fi -# Run tests -echo 'Running tests, please wait ⌛'; -pytest tests/ --maxfail=1; -if [ $? == 0 ]; then - echo 'Tests succeed!! 🎉'; -else - echo 'Tests failed 😓 PUSH ABORTED'; - echo 'Run `pytest -v --cov=capa test/` if you need more details'; - restore_stashed; - exit 4; +# Run tests except if first argument is no_tests +if [ "$1" != 'no_tests' ]; then + echo 'Running tests, please wait ⌛'; + pytest tests/ --maxfail=1; + if [ $? == 0 ]; then + echo 'Tests succeed!! 🎉'; + else + echo 'Tests FAILED! 😓'; + echo 'Run `pytest -v --cov=capa test/` if you need more details'; + restore_stashed; + exit 4; + fi fi -echo 'PUSH SUCCEEDED 🎉🎉'; - restore_stashed; +echo 'SUCCEEDED 🎉🎉'; + diff --git a/scripts/hooks/post-commit b/scripts/hooks/post-commit deleted file mode 100755 index b8d0892f..00000000 --- a/scripts/hooks/post-commit +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2020 FireEye, Inc. All Rights Reserved. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: [package root]/LICENSE.txt -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and limitations under the License. - -# Use a console with emojis support for a better experience - -# Stash uncommited changes -MSG="post-commit-$(date +%s)"; -git stash push -kum "$MSG" &>/dev/null ; -STASH_LIST=$(git stash list); -if [[ "$STASH_LIST" == *"$MSG"* ]]; then - echo "Uncommited changes stashed with message '$MSG', if you abort before they are restored run \`git stash pop\`"; -fi - -python_3() { - case "$(uname -s)" in - CYGWIN*|MINGW32*|MSYS*|MINGW*) - py -3 -m $1 > $2 2>&1;; - *) - python3 -m $1 > $2 2>&1;; - esac -} - -# Run isort and print state (it doesn't block the commit) -python_3 'isort --profile black --length-sort --line-width 120 -c .' 'isort-output.log'; -if [ $? == 0 ]; then - echo 'isort succeeded!! 💖'; -else - echo 'isort failed 😭'; - echo 'Check isort-output.log for details'; -fi - -# Run black and print state (it doesn't block the commit) -python_3 'black -l 120 --check .' 'black-output.log'; -if [ $? == 0 ]; then - echo 'black succeeded!! 💝'; -else - echo 'black failed 😭'; - echo 'Check black-output.log for details'; -fi - -# Run rule linter and print state (it doesn't block the commit) -python ./scripts/lint.py ./rules/ > rule-linter-output.log 2>&1; -if [ $? == 0 ]; then - echo 'Rule linter succeeded!! 💘'; -else - echo 'Rule linter failed 😭'; - echo 'Check rule-linter-output.log for details'; -fi - -# Restore stashed changes -if [[ "$STASH_LIST" == *"$MSG"* ]]; then - git stash pop --index &>/dev/null ; - echo "Stashed changes '$MSG' restored"; -fi diff --git a/scripts/setup-hooks.sh b/scripts/setup-hooks.sh index 04053956..5093b846 100755 --- a/scripts/setup-hooks.sh +++ b/scripts/setup-hooks.sh @@ -19,10 +19,10 @@ create_hook() { if [[ ! -e .git/hooks/$1 ]]; then echo "#!/usr/bin/env bash" > ".git/hooks/$1"; fi - cat scripts/hooks/"$1" >> ".git/hooks/$1"; + echo "scripts/ci.sh ${2:-}" >> ".git/hooks/$1"; chmod +x .git/hooks/"$1"; } -printf 'Copying hooks into .git/hooks'; -create_hook 'post-commit'; +printf 'Adding scripts/ci.sh to .git/hooks/'; +create_hook 'pre-commit' 'no_tests'; create_hook 'pre-push';