├── tests ├── err │ ├── file-empty_err │ ├── syntax-js_err.js │ ├── file-crlf_err │ ├── file-utf8-bom_err │ ├── file-cr_err │ ├── file-trailing-newline_err │ ├── syntax-json_err.json │ ├── file-trailing-space_err │ ├── syntax-css_err.css │ ├── syntax-scss_err.scss │ ├── file-utf8_err │ ├── syntax-ruby_err.rb │ ├── git-conflicts_err │ ├── inline-css_err.html │ ├── syntax-python_err.py │ ├── file-trailing-single-newline_err │ ├── syntax-php_err.php │ ├── inline-js_err.html │ ├── syntax-sh_err.sh │ ├── syntax-perl_err.pl │ ├── syntax-bash_err.bash │ ├── file-nullbyte-char_err.bin │ └── syntax-markdown_err.md ├── ok │ ├── file-empty_ok │ ├── file-utf8_ok │ ├── file-crlf_ok │ ├── file-utf8-bom_ok │ ├── file-trailing-space_ok │ ├── syntax-css_ok.css │ ├── syntax-sh_ok.sh │ ├── syntax-scss_ok.scss │ ├── file-trailing-newline_ok │ ├── syntax-js_ok.js │ ├── syntax-json_ok.json │ ├── syntax-ruby_ok.rb │ ├── syntax-bash_ok.bash │ ├── syntax-markdown_ok.md │ ├── file-trailing-single-newline_ok │ ├── inline-css_ok.html │ ├── inline-js_ok.html │ ├── syntax-php_ok.php │ ├── syntax-python_ok.py │ ├── syntax-perl_ok.pl │ ├── git-conflicts_ok │ └── file-nullbyte-char_ok.bin ├── README.md ├── test.sh └── test_single.sh ├── .gitignore ├── Dockerfiles ├── Dockerfile.alpine ├── Dockerfile.latest └── data │ ├── file-empty │ ├── aci-trailing-newline │ ├── git-conflicts │ ├── file-utf8 │ ├── file-trailing-newline │ ├── file-trailing-space │ ├── file-utf8-bom │ ├── file-crlf │ ├── file-trailing-single-newline │ ├── file-cr │ ├── file-nullbyte │ ├── usage │ └── awesome-ci-lib.sh ├── .github ├── dependabot.yml ├── labels.yml ├── workflows │ ├── release-drafter.yml │ ├── repository.yml │ ├── lint.yml │ ├── action_pull_request.yml │ ├── action_schedule.yml │ ├── action_branch.yml │ └── params.yml └── release-drafter.yml ├── .yamllint ├── LICENSE ├── Makefile └── README.md /tests/err/file-empty_err: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/ok/file-empty_ok: -------------------------------------------------------------------------------- 1 | Not empty 2 | -------------------------------------------------------------------------------- /tests/ok/file-utf8_ok: -------------------------------------------------------------------------------- 1 | Correct unicode 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.docker 2 | Makefile.lint 3 | -------------------------------------------------------------------------------- /Dockerfiles/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | Dockerfile.latest -------------------------------------------------------------------------------- /tests/err/syntax-js_err.js: -------------------------------------------------------------------------------- 1 | console.log({; 2 | -------------------------------------------------------------------------------- /tests/ok/file-crlf_ok: -------------------------------------------------------------------------------- 1 | LINE1 2 | LINE2 3 | LINE3 4 | -------------------------------------------------------------------------------- /tests/ok/file-utf8-bom_ok: -------------------------------------------------------------------------------- 1 | This file contains BOM 2 | -------------------------------------------------------------------------------- /tests/err/file-crlf_err: -------------------------------------------------------------------------------- 1 | LINE1 2 | LINE2 3 | LINE3 4 | -------------------------------------------------------------------------------- /tests/err/file-utf8-bom_err: -------------------------------------------------------------------------------- 1 | This file contains BOM 2 | -------------------------------------------------------------------------------- /tests/err/file-cr_err: -------------------------------------------------------------------------------- 1 | ------- MIIDuDCCAqACAQAwgegxCzAJBgNVBA 2 | -------------------------------------------------------------------------------- /tests/ok/file-trailing-space_ok: -------------------------------------------------------------------------------- 1 | No trailing 2 | space 3 | here 4 | -------------------------------------------------------------------------------- /tests/ok/syntax-css_ok.css: -------------------------------------------------------------------------------- 1 | .cla { 2 | padding-left:10px; 3 | } 4 | -------------------------------------------------------------------------------- /tests/ok/syntax-sh_ok.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | VARIABLE="test" 5 | -------------------------------------------------------------------------------- /tests/ok/syntax-scss_ok.scss: -------------------------------------------------------------------------------- 1 | .cla { 2 | padding-left:10px; 3 | } 4 | -------------------------------------------------------------------------------- /tests/err/file-trailing-newline_err: -------------------------------------------------------------------------------- 1 | This file does not have a trailing newline -------------------------------------------------------------------------------- /tests/err/syntax-json_err.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "hey": "hoe 4 | } 5 | -------------------------------------------------------------------------------- /tests/ok/file-trailing-newline_ok: -------------------------------------------------------------------------------- 1 | This file does have a trailing newline 2 | -------------------------------------------------------------------------------- /tests/ok/syntax-js_ok.js: -------------------------------------------------------------------------------- 1 | function foo(bar) { 2 | var foobar = 5; 3 | } 4 | -------------------------------------------------------------------------------- /tests/ok/syntax-json_ok.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": "bar", 3 | "hey": "hoe" 4 | } 5 | -------------------------------------------------------------------------------- /tests/ok/syntax-ruby_ok.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | puts 'Hello world' 4 | -------------------------------------------------------------------------------- /tests/err/file-trailing-space_err: -------------------------------------------------------------------------------- 1 | A lot 2 | of trailing 3 | space 4 | -------------------------------------------------------------------------------- /tests/ok/syntax-bash_ok.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | VARIABLE="test" 5 | -------------------------------------------------------------------------------- /tests/ok/syntax-markdown_ok.md: -------------------------------------------------------------------------------- 1 | # H1 2 | 3 | ## H2 4 | 5 | ### H3 6 | 7 | some text 8 | -------------------------------------------------------------------------------- /tests/err/syntax-css_err.css: -------------------------------------------------------------------------------- 1 | .cla, { 2 | padding-left:10px; 3 | },[ 4 | magin:10; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tests/ok/file-trailing-single-newline_ok: -------------------------------------------------------------------------------- 1 | This file does only have a single trailing newline, 2 | -------------------------------------------------------------------------------- /tests/ok/inline-css_ok.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 2 | 3 | 4 | 5 | 6 | >>>>>> branch-a 7 | -------------------------------------------------------------------------------- /tests/err/inline-css_err.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 2 | 3 | 4 | test 5 | 6 | >>>>>> 4 | >>>>>>>branch-a 5 | >>>>>>> branch-a 6 | 7 | <<<<<<< 8 | <<<<<< 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/action_pull_request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: build 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | pull_request: 14 | 15 | 16 | jobs: 17 | 18 | # (1/2) Determine repository params 19 | params: 20 | uses: ./.github/workflows/params.yml 21 | # Only run for forks (contributor) 22 | if: github.event.pull_request.head.repo.fork 23 | 24 | # (2/2) Build 25 | docker: 26 | needs: [params] 27 | uses: devilbox/github-actions/.github/workflows/docker-name-version-flavour-arch.yml@master 28 | with: 29 | enabled: true 30 | can_deploy: false 31 | matrix: ${{ needs.params.outputs.matrix }} 32 | refs: ${{ needs.params.outputs.refs }} 33 | secrets: 34 | dockerhub_username: "" 35 | dockerhub_password: "" 36 | -------------------------------------------------------------------------------- /.github/workflows/action_schedule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: nightly 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs daily 14 | schedule: 15 | - cron: '0 0 * * *' 16 | 17 | 18 | jobs: 19 | 20 | # (1/2) Determine repository params 21 | params: 22 | uses: ./.github/workflows/params.yml 23 | 24 | # (2/2) Build 25 | docker: 26 | needs: [params] 27 | uses: devilbox/github-actions/.github/workflows/docker-name-version-flavour-arch.yml@master 28 | with: 29 | enabled: true 30 | can_deploy: true 31 | matrix: ${{ needs.params.outputs.matrix }} 32 | refs: ${{ needs.params.outputs.refs }} 33 | secrets: 34 | dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} 35 | dockerhub_password: ${{ secrets.DOCKERHUB_PASSWORD }} 36 | -------------------------------------------------------------------------------- /.github/workflows/action_branch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: build 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | push: 14 | paths: 15 | - 'Makefile' 16 | - 'Dockerfiles/**' 17 | - 'tests/**' 18 | - '.github/workflows/action*.yml' 19 | - '.github/workflows/params.yml' 20 | 21 | jobs: 22 | 23 | # (1/2) Determine repository params 24 | params: 25 | uses: ./.github/workflows/params.yml 26 | 27 | # (2/2) Build 28 | docker: 29 | needs: [params] 30 | uses: devilbox/github-actions/.github/workflows/docker-name-version-flavour-arch.yml@master 31 | with: 32 | enabled: true 33 | can_deploy: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/release-') }} 34 | matrix: ${{ needs.params.outputs.matrix }} 35 | refs: ${{ needs.params.outputs.refs }} 36 | secrets: 37 | dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }} 38 | dockerhub_password: ${{ secrets.DOCKERHUB_PASSWORD }} 39 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-empty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-empty" 10 | MY_DESC="Scans recursively for files that are empty." 11 | MY_FINISH_OK="No empty files found." 12 | MY_FINISH_ERR="Found empty files." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_EMPTY_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="test ! -s \"\$1\" && echo \"\$1: Empty file.\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="echo \"test is a built-in shell command\"" 49 | 50 | 51 | ############################################################ 52 | # Source library 53 | ############################################################ 54 | 55 | . /usr/bin/awesome-ci-lib.sh 56 | -------------------------------------------------------------------------------- /Dockerfiles/data/aci-trailing-newline: -------------------------------------------------------------------------------- 1 | #!/bin/sh -u 2 | 3 | NAME="aci-trailing-newline" 4 | 5 | 6 | 7 | print_usage() { 8 | echo "Usage: ${NAME} -n file" 9 | echo " ${NAME} -1 file" 10 | echo " ${NAME} -v" 11 | echo 12 | echo "Validates if a file has at least 1 or exactly only 1 trailing newline." 13 | echo "Returns 0, if condition is met, otherwise > 0" 14 | echo 15 | echo " -n Must have at least 1 trailing newline at the end of the file." 16 | echo " -1 Must have exactly only 1 trailing newline at the end of the file." 17 | echo " -v Show version" 18 | exit 1 19 | } 20 | print_version() { 21 | echo "${NAME} v0.1 (2016-08-21)" 22 | echo "Written by cytopia " 23 | echo "https://github.com/cytopia" 24 | } 25 | 26 | if [ "${#}" = "1" ] && [ "${1}" = "-v" ]; then 27 | print_version 28 | exit 0 29 | fi 30 | 31 | if [ "${#}" != "2" ]; then 32 | print_usage 33 | exit 1 34 | fi 35 | if [ "${1}" != "-n" ] && [ "${1}" != "-1" ]; then 36 | print_usage 37 | exit 1 38 | fi 39 | 40 | OPTION="${1}" 41 | FILE="${2}" 42 | 43 | # 44 | # Validate file 45 | # 46 | if [ ! -f "${FILE}" ]; then 47 | echo "No such file: ${FILE}" 48 | exit 1 49 | fi 50 | if [ ! -r "${FILE}" ]; then 51 | echo "Cannot read file: ${FILE}" 52 | exit 1 53 | fi 54 | 55 | 56 | 57 | # No trailing newline at the end of the file 58 | if ! tail -c 1 "${FILE}" | grep -qE "^$"; then 59 | exit 2 60 | fi 61 | 62 | 63 | # Check if only 1 trailing newline 64 | if [ "${OPTION}" = "-1" ]; then 65 | 66 | # At least two newlines at the end of the file 67 | if tail -c 2 "${FILE}" | grep -qE "^$"; then 68 | exit 3 69 | fi 70 | 71 | fi 72 | 73 | exit 0 74 | -------------------------------------------------------------------------------- /Dockerfiles/data/git-conflicts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="git-conflicts" 10 | MY_DESC="Scans recursively for files containing git conflicts." 11 | MY_FINISH_OK="No files with git conflicts found." 12 | MY_FINISH_ERR="Found files with git conflicts." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="GIT_CONFLICTS_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | MY_REG="^(<<<<<<<|>>>>>>>)[[:space:]]." 42 | MY_CHECK="grep --color=always -inHE \"${MY_REG}\" \"\$1\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="grep -V | grep -E '([0-9]+\.+)+'" 49 | 50 | 51 | ############################################################ 52 | # Source library 53 | ############################################################ 54 | 55 | . /usr/bin/awesome-ci-lib.sh 56 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-utf8: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-utf8" 10 | MY_DESC="Scans recursively for files containing non UTF-8 encoding." 11 | MY_FINISH_OK="All files are UTF-8 encoded." 12 | MY_FINISH_ERR="Found files with non UTF-8 encoding." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_UTF8_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="isutf8" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs/sh and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="isutf8 \"\$1\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | MY_FIX_CMD="isutf8 \"\$1\" >/dev/null || (TERM=vt100 vi -u NONE -n -es -c \"set fileencoding=utf8\" -c \"wq\" \"\$1\" > /dev/tty && echo \"Fixing: \$1\" || echo \"FAILED: \$1\")" 48 | 49 | # Command to be displayed for --info 50 | MY_INFO="isutf8 --help | grep version" 51 | 52 | 53 | ############################################################ 54 | # Source library 55 | ############################################################ 56 | 57 | . /usr/bin/awesome-ci-lib.sh 58 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-trailing-newline: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-trailing-newline" 10 | MY_DESC="Scans recursively for files not containing a trailing newline." 11 | MY_FINISH_OK="All files have a trailing newline." 12 | MY_FINISH_ERR="Some files do not have a trailing newline." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_TRAILING_NEWLINE_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="aci-trailing-newline" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs/sh and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="aci-trailing-newline -n \"\$1\" || echo \"\$1: No trailing newline at EOF.\"" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | # Command for fixing 48 | MY_FIX_CMD="aci-trailing-newline -n \"\$1\" || (echo \"\" >> \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\")" 49 | 50 | # Command to be displayed for --info 51 | MY_INFO="aci-trailing-newline -v" 52 | 53 | 54 | ############################################################ 55 | # Source library 56 | ############################################################ 57 | 58 | . /usr/bin/awesome-ci-lib.sh 59 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-trailing-space: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-trailing-space" 10 | MY_DESC="Scans recursively for files containing trailing spaces." 11 | MY_FINISH_OK="No files with trailing spaces found." 12 | MY_FINISH_ERR="Files with trailing spaces found." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_TRAILING_SPACE_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | MY_REG="^.*[[:blank:]]+$" 42 | MY_CHECK="LC_ALL=C grep --color=always -inHE \"${MY_REG}\" \"\$1\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | # Command for fixing 48 | MY_FIX_CMD="grep --color=always -iqE \"${MY_REG}\" \"\$1\" && (sed -i\"\" \"s/[[:blank:]]*\$//\" \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\") || true" 49 | 50 | # Command to be displayed for --info 51 | MY_INFO="grep -V | grep -E '([0-9]+\.+)+'" 52 | 53 | 54 | ############################################################ 55 | # Source library 56 | ############################################################ 57 | 58 | . /usr/bin/awesome-ci-lib.sh 59 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-utf8-bom: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-utf8-bom" 10 | MY_DESC="Scans recursively for files containing UTF-8 BOM." 11 | MY_FINISH_OK="No files have UTF-8 (Byte Order Mark)." 12 | MY_FINISH_ERR="Found files with UTF-8 BOM (Byte Order Mark)." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_UTF8_BOM_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="awk" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="awk \"/^\xEF\xBB\xBF/ {print FILENAME} {nextfile}\" \"\$1\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | # Command for fixing 48 | MY_FIX_CMD="out=\"\$( awk \"/^\xEF\xBB\xBF/ {print FILENAME} {nextfile}\" \"\$1\" )\" || true; if [ \"\${out}\" != \"\" ]; then (sed -i\"\" -e \"1s/^\xEF\xBB\xBF//\" \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\"); fi" 49 | 50 | # Command to be displayed for --info 51 | MY_INFO="(awk -Wversion 2>/dev/null || awk --version 2>&1) | grep -E '(([0-9]+)(\.))+'" 52 | 53 | 54 | ############################################################ 55 | # Source library 56 | ############################################################ 57 | 58 | . /usr/bin/awesome-ci-lib.sh 59 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-crlf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-crlf" 10 | MY_DESC="Scans recursively for files containing CRLF (Windows Line Feeds)." 11 | MY_FINISH_OK="No files with CRLF (Windows Line Feed) found." 12 | MY_FINISH_ERR="Files with CRLF (Windows Line Feed) found." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_CRLF_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="file" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="dos2unix" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | MY_REG="[[:space:]]CRLF(,|[[:space:]].*line)" 42 | MY_CHECK="file \"\$1\" | grep --color=always -E \"${MY_REG}\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | MY_FIX_CMD="file \"\$1\" | grep -qE \"${MY_REG}\" && (dos2unix -k -q -s \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\") || true" 48 | 49 | # Command to be displayed for --info 50 | MY_INFO="file -v 2>&1 | grep -E '(([0-9]+)(\.))+'" 51 | 52 | # Command to be displayed for --info 53 | MY_FIX_INFO="dos2unix --version 2>&1 | grep -E 'dos2unix\s+[.0-9]+'" 54 | 55 | 56 | ############################################################ 57 | # Source library 58 | ############################################################ 59 | 60 | . /usr/bin/awesome-ci-lib.sh 61 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-trailing-single-newline: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-trailing-single-newline" 10 | MY_DESC="Scans recursively for files not containing exactly 1 trailing newline." 11 | MY_FINISH_OK="All files have exactly one trailing newline." 12 | MY_FINISH_ERR="Some files do not have exactly one trailing newline." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_TRAILING_SINGLE_NEWLINE_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="aci-trailing-newline" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="aci-trailing-newline -1 \"\$1\" || echo \"\$1: Not exactly one trailing newline at EOF.\"" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | # Command for fixing 48 | MY_FIX_CMD="aci-trailing-newline -1 \"\$1\" || ((echo \"\" >> \"\$1\" && sed -i\"\" -e :a -e \"/^\n*\\\$/{\\\$d;N;ba\" -e \"}\" \"\$1\") && echo \"Fixing: \$1\" || echo \"FAILED: \$1\")" 49 | 50 | # Command to be displayed for --info 51 | MY_INFO="aci-trailing-newline -v" 52 | 53 | 54 | ############################################################ 55 | # Source library 56 | ############################################################ 57 | 58 | . /usr/bin/awesome-ci-lib.sh 59 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-cr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-cr" 10 | MY_DESC="Scans recursively for files containing CR (Carriage Return only Line Feeds)." 11 | MY_FINISH_OK="No files with CR (Carriage Return only Line Feed) found." 12 | MY_FINISH_ERR="Files with CR (Carriage Return Line Feed) found." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_CR_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="file" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | MY_REG="[[:space:]]CR(,)?[[:space:]].*line" 42 | MY_CHECK="file \"\$1\" | grep --color=always -E \"${MY_REG}\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=1 46 | 47 | MY_FIX_CMD="file \"\$1\" | grep -qE \"${MY_REG}\" && (TERM=vt100 vi -u NONE -n -es -c \"%s/\r/\r/g\" -c \"wq\" \"\$1\" > /dev/tty && echo \"Fixing: \$1\" || echo \"FAILED: \$1\") || true" 48 | 49 | # Command to be displayed for --info 50 | MY_INFO="file -v 2>&1 | grep -E '(([0-9]+)(\.))+'" 51 | 52 | # Command to be displayed for --info 53 | MY_FIX_INFO="" 54 | 55 | 56 | ############################################################ 57 | # Source library 58 | ############################################################ 59 | 60 | . /usr/bin/awesome-ci-lib.sh 61 | -------------------------------------------------------------------------------- /.github/workflows/params.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: params 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # Custom Variables 11 | # ------------------------------------------------------------------------------------------------- 12 | env: 13 | MATRIX: >- 14 | [ 15 | { 16 | "NAME": "fl", 17 | "VERSION": ["latest"], 18 | "FLAVOUR": ["alpine", "latest"], 19 | "ARCH": ["linux/amd64", "linux/386", "linux/arm64", "linux/arm/v7", "linux/arm/v6"] 20 | } 21 | ] 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # When to run 26 | # ------------------------------------------------------------------------------------------------- 27 | on: 28 | workflow_call: 29 | outputs: 30 | matrix: 31 | description: "The determined version matrix" 32 | value: ${{ jobs.params.outputs.matrix }} 33 | refs: 34 | description: "The determined git ref matrix (only during scheduled run)" 35 | value: ${{ jobs.params.outputs.refs }} 36 | 37 | jobs: 38 | params: 39 | runs-on: ubuntu-latest 40 | 41 | outputs: 42 | matrix: ${{ steps.set-matrix.outputs.matrix }} 43 | refs: ${{ steps.set-refs.outputs.matrix }} 44 | 45 | steps: 46 | - name: "[Set-Output] Matrix" 47 | id: set-matrix 48 | run: | 49 | echo "matrix=$( echo '${{ env.MATRIX }}' | jq -M -c )" >> $GITHUB_OUTPUT 50 | 51 | - name: "[Set-Output] Matrix 'Refs' (master branch and latest tag)" 52 | id: set-refs 53 | uses: cytopia/git-ref-matrix-action@v0.1.13 54 | with: 55 | repository_default_branch: master 56 | branches: master 57 | num_latest_tags: 0 58 | if: github.event_name == 'schedule' 59 | 60 | - name: "[DEBUG] Show settings'" 61 | run: | 62 | echo 'Matrix' 63 | echo '--------------------' 64 | echo '${{ steps.set-matrix.outputs.matrix }}' 65 | echo 66 | 67 | echo 'Matrix: Refs' 68 | echo '--------------------' 69 | echo '${{ steps.set-matrix-refs.outputs.matrix }}' 70 | echo 71 | -------------------------------------------------------------------------------- /Dockerfiles/data/file-nullbyte: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-nullbyte" 10 | MY_DESC="Scans recursively for files containing a null-byte characters (\x00)." 11 | MY_FINISH_OK="No files with null-byte (\x00) characters found." 12 | MY_FINISH_ERR="Files with null-byte (\x00) characters found." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_NULLBYTE_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | MY_REG="\x0" 42 | #MY_CHECK="if cat -n \"\$1\" | sed -n \"/${MY_REG}/p\" | grep -aq \"^[[:space:]]*[0-9]\"; then printf \"\$1:\"; cat -n \"\$1\" | sed -n \"/${MY_REG}/p\" | sed \"s/^[[:space:]]*//g\"; else true; fi" 43 | MY_CHECK="if cat \"\$1\" | sed -n \"/${MY_REG}/p\" | wc -l | grep -q \"^[1-9]\"; then cat \"\$1\" | sed -n \"/${MY_REG}/p\" | sed \"s/^[[:space:]]*//g\" | sed -e \"s|^|\$1:|\"; else true; fi" 44 | 45 | # Can this check fix the problems? 46 | ENABLE_FIX=1 47 | 48 | #MY_FIX_CMD="grep -aq \"${MY_REG}\" \"\$1\" && (sed -i\"\" \"s/${MY_REG}//g\" \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\") || true" 49 | MY_FIX_CMD="if cat \"\$1\" | sed -n \"/${MY_REG}/p\" | grep -aq \"^[[:space:]]*[0-9]\"; then (sed -i\"\" \"s/${MY_REG}//g\" \"\$1\" && echo \"Fixing: \$1\" || echo \"FAILED: \$1\"); else true; fi" 50 | 51 | # Command to be displayed for --info 52 | MY_INFO="file -v 2>&1 | grep -E '(([0-9]+)(\.))+'" 53 | 54 | # Command to be displayed for --info 55 | MY_FIX_INFO="" 56 | 57 | 58 | ############################################################ 59 | # Source library 60 | ############################################################ 61 | 62 | . /usr/bin/awesome-ci-lib.sh 63 | -------------------------------------------------------------------------------- /Dockerfiles/data/usage: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "################################################################################" 4 | echo "# cytopia/file-lint #" 5 | echo "# (awesome-ci) #" 6 | echo "################################################################################" 7 | echo "# #" 8 | echo "# #" 9 | echo "# Usage: #" 10 | echo "# -----------------------------------------------------------------------------#" 11 | echo "# docker run --rm cytopia/file-lint --help #" 12 | echo "# docker run --rm cytopia/file-lint --help #" 13 | echo "# docker run --rm cytopia/file-lint --info #" 14 | echo "# docker run --rm cytopia/file-lint --version #" 15 | echo "# #" 16 | echo "# #" 17 | echo "# Available tools: #" 18 | echo "# -----------------------------------------------------------------------------#" 19 | echo "# file-empty Scans if files are empty #" 20 | echo "# file-cr Scans if files contain carriage returns (\\r) #" 21 | echo "# file-crlf Scans if files contain win line feeds (\\r\\n) #" 22 | echo "# file-nullbyte Scans if files contain nullbyte chars (\\x00) #" 23 | echo "# file-trailing-newline Scans if files contain trailing newline(s) #" 24 | echo "# file-trailing-single-newline Scans if files contain single trailing newline #" 25 | echo "# file-trailing-space Scans if files contain trailing whitespace #" 26 | echo "# file-utf8 Scans if files are utf8 encoded #" 27 | echo "# file-utf8-bom Scans if files contain byte order mark #" 28 | echo "# git-conflicts Scans if files contain git conflicts #" 29 | echo "# #" 30 | echo "# #" 31 | echo "# Example: #" 32 | echo "# -----------------------------------------------------------------------------#" 33 | echo "# docker run --rm -v \$(pwd):/data cytopia/file-lint \\ #" 34 | echo "# lf-crlf --ignore \".git/,.github/\" --path . #" 35 | echo "# #" 36 | echo "################################################################################" 37 | echo 38 | -------------------------------------------------------------------------------- /tests/test_single.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | ### 9 | ### Define Paths 10 | ### 11 | GIT_PATH="$( cd "$(dirname "$0")" ; pwd -P )/.." 12 | ETC_PATH="${GIT_PATH}/etc/awesome-ci.conf" 13 | BIN_PATH="${GIT_PATH}/bin" 14 | 15 | TEST_SUCC_PATH="${GIT_PATH}/test/ok" 16 | TEST_FAIL_PATH="${GIT_PATH}/test/err" 17 | 18 | # Add dependencies to path 19 | PATH=${GIT_PATH}/dependencies:${PATH} 20 | 21 | 22 | ### 23 | ### Check arguments 24 | ### 25 | if [ "${#}" -ne "1" ]; then 26 | >&2 echo "This script requires exactly one argument: ${#} are given." 27 | exit 1 28 | fi 29 | 30 | # Path to binary 31 | BINARY="${BIN_PATH}/${1}" 32 | 33 | 34 | ############################################################ 35 | # Functions 36 | ############################################################ 37 | 38 | run () { 39 | local cmd="${1}" 40 | 41 | >&2 echo "----------------------------------------------------------------------------------------------------" 42 | >&2 echo "\$ ${cmd}" 43 | >&2 echo "----------------------------------------------------------------------------------------------------" 44 | 45 | ${cmd} 46 | } 47 | 48 | 49 | ############################################################ 50 | # Run tests 51 | ############################################################ 52 | 53 | 54 | ### 55 | ### 1. Info 56 | ### 57 | COMMAND="${BINARY} --info" 58 | if ! OUT="$( run "${COMMAND}" )"; then 59 | echo "${OUT}" 60 | >&2 echo "[Error] 'Info test' failed" 61 | exit 1 62 | fi 63 | echo "[TEST PASSED]" 64 | echo 65 | 66 | 67 | ### 68 | ### 2. Dry 69 | ### 70 | if [ "${1}" = "git-ignored" ]; then 71 | COMMAND="${BINARY} --path=. --dry" 72 | else 73 | COMMAND="${BINARY} --path=. --config=${ETC_PATH} --dry" 74 | fi 75 | if ! OUT="$( run "${COMMAND}" )"; then 76 | echo "${OUT}" 77 | >&2 echo "[TEST FAILED] 'Dry test' failed" 78 | exit 1 79 | fi 80 | echo "[TEST PASSED]" 81 | echo 82 | 83 | 84 | ### 85 | ### 3. Test OK 86 | ### 87 | if [ "${1}" != "git-ignored" ] && [ "${1}" != "regex-grep" ] && [ "${1}" != "regex-perl" ]; then 88 | 89 | COMMAND="${BINARY} --path=${TEST_SUCC_PATH} --config=${ETC_PATH}" 90 | 91 | if ! OUT="$( run "${COMMAND} --list" )"; then 92 | echo "${OUT}" 93 | >&2 echo "[TEST FAILED] 'Success test' failed" 94 | exit 1 95 | fi 96 | echo "[TEST PASSED]" 97 | echo 98 | 99 | if ! OUT="$( run "${COMMAND} --verbose" )"; then 100 | echo "${OUT}" 101 | >&2 echo "[TEST FAILED] 'Success test' failed" 102 | exit 1 103 | fi 104 | echo "[TEST PASSED]" 105 | echo 106 | 107 | if ! OUT="$( run "${COMMAND}" )"; then 108 | echo "${OUT}" 109 | >&2 echo "[TEST FAILED] 'Success test' failed" 110 | exit 1 111 | fi 112 | echo "[TEST PASSED]" 113 | echo 114 | fi 115 | 116 | 117 | ### 118 | ### 3. Test Failure 119 | ### 120 | if [ "${1}" != "git-ignored" ] && [ "${1}" != "regex-grep" ] && [ "${1}" != "regex-perl" ]; then 121 | 122 | COMMAND="${BINARY} --path=${TEST_FAIL_PATH} --config=${ETC_PATH}" 123 | 124 | if ! OUT="$( run "${COMMAND} --verbose" )"; then 125 | echo "[TEST PASSED]" 126 | echo 127 | else 128 | echo "${OUT}" 129 | >&2 echo "[TEST FAILED] 'Failure test' failed" 130 | exit 1 131 | fi 132 | 133 | if ! OUT="$( run "${COMMAND}" )"; then 134 | echo "[TEST PASSED]" 135 | echo 136 | else 137 | echo "${OUT}" 138 | >&2 echo "[TEST FAILED] 'Failure test' failed" 139 | exit 1 140 | fi 141 | fi 142 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifneq (,) 2 | .error This Makefile requires GNU Make. 3 | endif 4 | 5 | # Ensure additional Makefiles are present 6 | MAKEFILES = Makefile.docker Makefile.lint 7 | $(MAKEFILES): URL=https://raw.githubusercontent.com/devilbox/makefiles/master/$(@) 8 | $(MAKEFILES): 9 | @if ! (curl --fail -sS -o $(@) $(URL) || wget -O $(@) $(URL)); then \ 10 | echo "Error, curl or wget required."; \ 11 | echo "Exiting."; \ 12 | false; \ 13 | fi 14 | include $(MAKEFILES) 15 | 16 | # Set default Target 17 | .DEFAULT_GOAL := help 18 | 19 | 20 | # ------------------------------------------------------------------------------------------------- 21 | # Default configuration 22 | # ------------------------------------------------------------------------------------------------- 23 | # Own vars 24 | TAG = latest 25 | 26 | # Makefile.docker overwrites 27 | NAME = file-lint 28 | VERSION = latest 29 | IMAGE = cytopia/file-lint 30 | FLAVOUR = latest 31 | FILE = Dockerfile.${FLAVOUR} 32 | DIR = Dockerfiles 33 | 34 | # Building from master branch: Tag == 'latest' 35 | ifeq ($(strip $(TAG)),latest) 36 | ifeq ($(strip $(VERSION)),latest) 37 | DOCKER_TAG = $(FLAVOUR) 38 | else 39 | ifeq ($(strip $(FLAVOUR)),latest) 40 | DOCKER_TAG = $(VERSION) 41 | else 42 | DOCKER_TAG = $(FLAVOUR)-$(VERSION) 43 | endif 44 | endif 45 | # Building from any other branch or tag: Tag == '' 46 | else 47 | ifeq ($(strip $(FLAVOUR)),latest) 48 | DOCKER_TAG = $(VERSION)-$(TAG) 49 | else 50 | DOCKER_TAG = $(FLAVOUR)-$(VERSION)-$(TAG) 51 | endif 52 | endif 53 | 54 | # Makefile.lint overwrites 55 | FL_IGNORES = .git/,.github/,tests/ 56 | SC_IGNORES = .git/,.github/,tests/,Dockerfiles/data/awesome-ci-lib.sh 57 | JL_IGNORES = .git/,.github/,./tests/ 58 | 59 | 60 | # ------------------------------------------------------------------------------------------------- 61 | # Default Target 62 | # ------------------------------------------------------------------------------------------------- 63 | .PHONY: help 64 | help: 65 | @echo "lint Lint project files and repository" 66 | @echo 67 | @echo "build [ARCH=...] [TAG=...] Build Docker image" 68 | @echo "rebuild [ARCH=...] [TAG=...] Build Docker image without cache" 69 | @echo "push [ARCH=...] [TAG=...] Push Docker image to Docker hub" 70 | @echo 71 | @echo "manifest-create [ARCHES=...] [TAG=...] Create multi-arch manifest" 72 | @echo "manifest-push [TAG=...] Push multi-arch manifest" 73 | @echo 74 | @echo "test [ARCH=...] Test built Docker image" 75 | @echo 76 | 77 | 78 | # ------------------------------------------------------------------------------------------------- 79 | # Docker Targets 80 | # ------------------------------------------------------------------------------------------------- 81 | .PHONY: build 82 | build: ARGS=--build-arg VERSION=$(VERSION) 83 | build: docker-arch-build 84 | 85 | .PHONY: rebuild 86 | rebuild: ARGS=--build-arg VERSION=$(VERSION) 87 | rebuild: docker-arch-rebuild 88 | 89 | .PHONY: push 90 | push: docker-arch-push 91 | 92 | 93 | # ------------------------------------------------------------------------------------------------- 94 | # Manifest Targets 95 | # ------------------------------------------------------------------------------------------------- 96 | .PHONY: manifest-create 97 | manifest-create: docker-manifest-create 98 | 99 | .PHONY: manifest-push 100 | manifest-push: docker-manifest-push 101 | 102 | 103 | # ------------------------------------------------------------------------------------------------- 104 | # Test Targets 105 | # ------------------------------------------------------------------------------------------------- 106 | .PHONY: test 107 | test: _test-req 108 | test: _test-run-succ 109 | test: _test-run-fail 110 | 111 | _test-req: 112 | @echo "------------------------------------------------------------" 113 | @echo "- Testing requirements" 114 | @echo "------------------------------------------------------------" 115 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-empty --info 116 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-cr --info 117 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-crlf --info 118 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-nullbyte --info 119 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-trailing-newline --info 120 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-trailing-single-newline --info 121 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-trailing-space --info 122 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-utf8 --info 123 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) file-utf8-bom --info 124 | docker run --rm --platform $(ARCH) $(IMAGE):$(DOCKER_TAG) git-conflicts --info 125 | 126 | _test-run-succ: 127 | @echo "------------------------------------------------------------" 128 | @echo "- Runtime test: False positives" 129 | @echo "------------------------------------------------------------" 130 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-empty --path . 131 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-cr --path . 132 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-crlf --path . 133 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-nullbyte --path . 134 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-trailing-newline --path . 135 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-trailing-single-newline --path . 136 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-trailing-space --path . 137 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-utf8 --path . 138 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) file-utf8-bom --path . 139 | @docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/ok:/data $(IMAGE):$(DOCKER_TAG) git-conflicts --path . 140 | 141 | _test-run-fail: 142 | @echo "------------------------------------------------------------" 143 | @echo "- Runtime test: True flaws" 144 | @echo "------------------------------------------------------------" 145 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-empty --path .; then \ 146 | exit 1; \ 147 | fi 148 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-cr --path .; then \ 149 | exit 1; \ 150 | fi 151 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-crlf --path .; then \ 152 | exit 1; \ 153 | fi 154 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-nullbyte --path .; then \ 155 | exit 1; \ 156 | fi 157 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-trailing-newline --path .; then \ 158 | exit 1; \ 159 | fi 160 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-trailing-single-newline --path .; then \ 161 | exit 1; \ 162 | fi 163 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-trailing-space --path .; then \ 164 | exit 1; \ 165 | fi 166 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-utf8 --path .; then \ 167 | exit 1; \ 168 | fi 169 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) file-utf8-bom --path .; then \ 170 | exit 1; \ 171 | fi 172 | @if docker run --rm --platform $(ARCH) -v $(CURRENT_DIR)/tests/err:/data $(IMAGE):$(DOCKER_TAG) git-conflicts --path .; then \ 173 | exit 1; \ 174 | fi 175 | -------------------------------------------------------------------------------- /Dockerfiles/data/awesome-ci-lib.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | # 5 | # Version 6 | # 7 | MY_VERSION="0.18" 8 | MY_DATE="2022-20-28" 9 | 10 | # 11 | # Credits 12 | # 13 | MY_AUTHOR="cytopia" 14 | MY_EMAIL="cytopia@everythingcli.org" 15 | 16 | # 17 | # Required system binaries 18 | # 19 | REQUIRED_BINS="awk grep find sed tr xargs" 20 | 21 | # 22 | # Variables populated by cmd args or config file 23 | # 24 | MY_PATH= 25 | MY_SHE= 26 | MY_EXT=0 27 | MY_IGN= 28 | MY_TXT=0 29 | MY_SIZ=0 30 | MY_DRY=0 31 | MY_LST=0 32 | MY_VER=0 33 | MY_DEB=0 34 | MY_FIX=0 35 | MY_CFG= 36 | MY_CUS= 37 | 38 | CLR_SUC="\033[0;32m" 39 | CLR_ERR="\033[0;31m" 40 | CLR_CLS="\033[0m" 41 | 42 | ################################################################################ 43 | # 44 | # F U N C T I O N S 45 | # 46 | ################################################################################ 47 | 48 | 49 | 50 | print_usage() { 51 | 52 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 53 | _custom=" [--custom \"opts\"]" 54 | else 55 | _custom="" 56 | fi 57 | 58 | if [ "${ENABLE_FIX}" = "1" ];then 59 | _fix=" [--fix]" 60 | else 61 | _fix="" 62 | fi 63 | 64 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang ] [--extension \"tpl,htm,html,php,...\"] [--ignore \"dir1,dir2\"] [--config \"conf\"] [--confpre \"${MY_CONF_PRE}\"]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path " 65 | echo " ${MY_NAME} --info" 66 | echo " ${MY_NAME} --help" 67 | echo " ${MY_NAME} --version" 68 | echo 69 | echo "${MY_DESC}" 70 | echo "Will return 1 on occurance, otherwise 0." 71 | echo 72 | echo "Required arguments:" 73 | echo 74 | echo " --path Specify directory where to scan." 75 | echo 76 | echo 77 | echo "Optional run arguments:" 78 | if [ "${ENABLE_FIX}" = "1" ];then 79 | echo " --fix Fixable :-)" 80 | echo " Fix the problems for the specified files." 81 | echo " Note, all other options below also apply" 82 | echo 83 | fi 84 | echo " --text Limit search to text files only (non-binary)." 85 | echo " Can be narrowed further with '--extension'" 86 | echo 87 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 88 | echo 89 | echo " --shebang Only find files (shell scripts) with this specific shebang." 90 | echo " It is useful to combine this with --text and --size for faster searches." 91 | echo " Use with --dry to see how this search command is generated." 92 | echo " Example:" 93 | echo " --shebang bash" 94 | echo " --shebang php" 95 | echo " --shebang sh" 96 | echo 97 | echo " --extension Only find files matching those extensions." 98 | echo " Comma separated list of file extensions." 99 | echo " Only find files matching those extensions." 100 | echo " Defaults to all files if not specified or empty." 101 | echo " Example:" 102 | echo " --extension \"html,php,inc\"" 103 | echo " --extension php" 104 | echo 105 | echo " --ignore Comma separated list of ignore paths." 106 | echo " Directories must be specified from the starting location of --path." 107 | echo " Example:" 108 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 109 | echo " --path /var/www --ignore foo/bar" 110 | echo 111 | echo " --config Load configuration file." 112 | echo " File must contain the following directives:" 113 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 114 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 115 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 116 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 117 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 118 | fi 119 | echo " Note that cmd arguments take precedence over" 120 | echo " config file settings." 121 | echo 122 | echo " --confpre Set custom configuration directive prefix." 123 | echo " Current default ist: '${MY_CONF_PRE}'." 124 | echo " This is useful, when you want to define different defaults" 125 | echo " per check via configuration file." 126 | echo 127 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 128 | echo " --custom Parse custom command line option to the check binary." 129 | echo " Note that when you want to add config files or other files" 130 | echo " you must use an absolute path." 131 | echo 132 | echo " Current custom command:" 133 | echo " --custom \"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 134 | echo 135 | echo " Overwrite example:" 136 | echo " --custom \"--color --config /absoulte/path/conf.json\"" 137 | echo 138 | fi 139 | echo " --verbose Be verbose and print commands and files being checked." 140 | echo 141 | echo 142 | echo " --debug Print system messages." 143 | echo 144 | echo 145 | echo "Optional training arguments:" 146 | echo " --dry Don't do anything, just display the commands." 147 | echo 148 | echo " --list Instead of searching inside the files, just display the filenames" 149 | echo " that would be found by --path, --extension and --ignore" 150 | echo 151 | echo 152 | echo "System arguments:" 153 | echo " --info Show versions of required commands (useful for bugreports)." 154 | echo " --help Show help screen." 155 | echo " --version Show version information." 156 | echo 157 | echo 158 | echo "${MY_NAME} is part of the awesome-ci collection." 159 | echo "https://github.com/cytopia/awesome-ci" 160 | } 161 | 162 | print_version() { 163 | echo "tool: ${MY_NAME}" 164 | echo "version: v${MY_VERSION} (${MY_DATE})" 165 | echo "author: ${MY_AUTHOR}" 166 | echo "email: ${MY_EMAIL}" 167 | echo 168 | echo "${MY_NAME} is part of the awesome-ci collection." 169 | echo "https://github.com/cytopia/awesome-ci" 170 | } 171 | 172 | print_info() { 173 | 174 | # 175 | # Required binaries 176 | # 177 | 178 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 179 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 180 | echo "\$ ${MY_CMD_VERSION}" 181 | eval "${MY_CMD_VERSION}" 182 | echo 183 | fi 184 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 185 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version 2>&1) | grep -E '(([0-9]+)(\.))+'" 186 | echo "\$ ${MY_CMD_VERSION}" 187 | eval "${MY_CMD_VERSION}" 188 | echo 189 | fi 190 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 191 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 192 | echo "\$ ${MY_CMD_VERSION}" 193 | eval "${MY_CMD_VERSION}" 194 | echo 195 | fi 196 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 197 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 198 | echo "\$ ${MY_CMD_VERSION}" 199 | eval "${MY_CMD_VERSION}" 200 | echo 201 | fi 202 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 203 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 204 | echo "\$ ${MY_CMD_VERSION}" 205 | eval "${MY_CMD_VERSION}" 206 | echo 207 | fi 208 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 209 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 210 | echo "\$ ${MY_CMD_VERSION}" 211 | eval "${MY_CMD_VERSION}" 212 | echo 213 | fi 214 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 215 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 216 | echo "\$ ${MY_CMD_VERSION}" 217 | eval "${MY_CMD_VERSION}" 218 | echo 219 | fi 220 | 221 | # 222 | # Custom binary 223 | # 224 | if [ "${MY_INFO}" != "" ]; then 225 | echo "\$ ${MY_INFO}" 226 | eval "${MY_INFO}" 227 | echo 228 | fi 229 | 230 | # 231 | # --fix binary 232 | # 233 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 234 | _can_fix="1" 235 | for _bin in ${REQUIRED_FIX_BINS}; do 236 | if ! command -v "${_bin}" >/dev/null 2>&1; then 237 | echo "${_bin}: Not found." 238 | _can_fix="0}" 239 | fi 240 | done 241 | if [ "${_can_fix}" = "1" ]; then 242 | echo "\$ ${MY_FIX_INFO}" 243 | eval "${MY_FIX_INFO}" 244 | echo 245 | else 246 | echo "Unable to use --fix" 247 | echo 248 | return 0 249 | fi 250 | fi 251 | } 252 | 253 | 254 | check_requirements() { 255 | _debug="${1}" 256 | _ret1=0 257 | _ret2=0 258 | 259 | # System binaries 260 | for _bin in ${REQUIRED_BINS}; do 261 | if ! command -v "${_bin}" >/dev/null 2>&1; then 262 | echo "[ERR] Required sys binary '${_bin}' not found." 263 | _ret1=1 264 | else 265 | if [ "${_debug}" = "1" ]; then 266 | echo "[OK] Required system binary '${_bin}' found." 267 | fi 268 | fi 269 | done 270 | 271 | # Specific binaries for this check 272 | for _bin in ${REQUIRED_CUST_BINS}; do 273 | if ! command -v "${_bin}" >/dev/null 2>&1; then 274 | echo "[ERR] Required custom binary '${_bin}' not found." 275 | _ret2=1 276 | else 277 | if [ "${_debug}" = "1" ]; then 278 | echo "[OK] Required custom binary '${_bin}' found." 279 | fi 280 | fi 281 | done 282 | 283 | # Binaries required to fix 284 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 285 | for _bin in ${REQUIRED_FIX_BINS}; do 286 | if ! command -v "${_bin}" >/dev/null 2>&1; then 287 | echo "[ERR] Required --fix binary '${_bin}' not found." 288 | _ret2=1 289 | else 290 | if [ "${_debug}" = "1" ]; then 291 | echo "[OK] Required --fix binary '${_bin}' found." 292 | fi 293 | fi 294 | done 295 | fi 296 | 297 | 298 | return $((_ret1 + _ret2)) 299 | } 300 | 301 | check_config_file() { 302 | _config="${1}" 303 | 304 | # Check config file 305 | if [ ! -f "${_config}" ]; then 306 | echo "[CONFIG] Config file not found: ${_config}" 307 | return 1 308 | fi 309 | 310 | # Check directives 311 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 312 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 313 | return 1 314 | fi 315 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 316 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 317 | return 1 318 | fi 319 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 320 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 321 | return 1 322 | fi 323 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 324 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 325 | return 1 326 | fi 327 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 328 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 329 | return 1 330 | fi 331 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 332 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 333 | return 1 334 | fi 335 | 336 | # Check optional directives 337 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 338 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 339 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 340 | return 1 341 | fi 342 | fi 343 | 344 | } 345 | 346 | 347 | # 348 | # System independent method 349 | # to get number of CPU cores. 350 | # (defaults to 1 if impossible) 351 | # 352 | num_cpu() { 353 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 354 | echo "1" 355 | else 356 | echo "${_num}" 357 | fi 358 | } 359 | 360 | 361 | # 362 | # sed wrapper that automatically escapes 363 | # regex literals 364 | # 365 | mysed() { 366 | _input="$1" 367 | _search="$2" 368 | _replace="$3" 369 | 370 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 371 | } 372 | 373 | 374 | 375 | 376 | ################################################################################ 377 | # 378 | # M A I N E N T R Y P O I N T 379 | # 380 | ################################################################################ 381 | 382 | 383 | 384 | ############################################################ 385 | # Command Line arguments 386 | ############################################################ 387 | 388 | 389 | # 390 | # Read command line arguments 391 | # 392 | while [ $# -gt 0 ]; do 393 | case "${1}" in 394 | 395 | # ---------------------------------------- 396 | --path) 397 | shift 398 | MY_PATH="${1}" 399 | ;; 400 | 401 | # ---------------------------------------- 402 | --shebang) 403 | shift 404 | MY_SHE="${1}" 405 | ;; 406 | 407 | # ---------------------------------------- 408 | --extension) 409 | shift 410 | MY_EXT="${1}" 411 | ;; 412 | 413 | # ---------------------------------------- 414 | --ignore) 415 | shift 416 | MY_IGN="${1}" 417 | ;; 418 | 419 | # ---------------------------------------- 420 | --config) 421 | shift 422 | MY_CFG="${1}" 423 | ;; 424 | 425 | # ---------------------------------------- 426 | --confpre) 427 | shift 428 | MY_CONF_PRE="${1}" 429 | ;; 430 | 431 | # ---------------------------------------- 432 | --custom) 433 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 434 | shift 435 | MY_CUS="${1}" 436 | else 437 | echo "Invalid argument: ${1}" 438 | echo "Type '${MY_NAME} --help' for available options." 439 | exit 1 440 | fi 441 | ;; 442 | 443 | # ---------------------------------------- 444 | --fix) 445 | if [ "${ENABLE_FIX}" = "1" ]; then 446 | MY_FIX=1 447 | else 448 | echo "Invalid argument: ${1}" 449 | echo "Type '${MY_NAME} --help' for available options." 450 | exit 1 451 | fi 452 | ;; 453 | 454 | 455 | # ---------------------------------------- 456 | --text) 457 | MY_TXT=1 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --size) 462 | MY_SIZ=1 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --dry) 467 | MY_DRY=1 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --list) 472 | MY_LST=1 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --verbose) 477 | MY_VER=1 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --debug) 482 | MY_DEB=1 483 | ;; 484 | 485 | # ---------------------------------------- 486 | --info) 487 | if ! check_requirements "${MY_DEB}"; then 488 | exit 1 489 | fi 490 | 491 | if ! print_info; then 492 | exit 1 493 | fi 494 | 495 | exit 0 496 | ;; 497 | 498 | # ---------------------------------------- 499 | --help) 500 | print_usage 501 | exit 0 502 | ;; 503 | 504 | # ---------------------------------------- 505 | --version) 506 | print_version 507 | exit 0 508 | ;; 509 | 510 | # ---------------------------------------- 511 | *) 512 | echo "Invalid argument: ${1}" 513 | echo "Type '${MY_NAME} --help' for available options." 514 | exit 1 515 | ;; 516 | esac 517 | shift 518 | done 519 | 520 | 521 | 522 | ############################################################ 523 | # Sanity Checks 524 | ############################################################ 525 | 526 | # 527 | # Check general requirements 528 | # 529 | if ! check_requirements "${MY_DEB}"; then 530 | exit 1 531 | fi 532 | 533 | # 534 | # Check path 535 | # 536 | if [ "${MY_PATH}" = "" ]; then 537 | echo "--path not specified" 538 | echo "Type '${MY_NAME} --help' for available options." 539 | exit 1 540 | fi 541 | if [ ! -e "${MY_PATH}" ]; then 542 | echo "Specified path does not exist: '${MY_PATH}'." 543 | echo "Type '${MY_NAME} --help' for available options." 544 | exit 1 545 | fi 546 | 547 | 548 | # 549 | # Check and load config if desired 550 | # 551 | if [ "${MY_CFG}" != "" ]; then 552 | if ! check_config_file "${MY_CFG}"; then 553 | exit 1 554 | fi 555 | 556 | . "${MY_CFG}" 557 | fi 558 | 559 | 560 | 561 | ############################################################ 562 | # Evaluate Settings 563 | ############################################################ 564 | 565 | CPU_CORES="$(num_cpu)" 566 | 567 | 568 | # Var substitutions for config file directives 569 | # to match current program. 570 | EXTENSION="${MY_CONF_PRE}EXTENSION" 571 | IGNORE="${MY_CONF_PRE}IGNORE" 572 | TEXT="${MY_CONF_PRE}TEXT" 573 | SIZE="${MY_CONF_PRE}SIZE" 574 | CUSTOM="${MY_CONF_PRE}CUSTOM" 575 | 576 | # 577 | # Decide on Shebang 578 | # 579 | if [ "${MY_SHE}" != "" ]; then 580 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 581 | else 582 | MY_SHE="" 583 | fi 584 | 585 | 586 | 587 | # 588 | # Decide on File extensions 589 | # 590 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 591 | if [ "${MY_DEB}" = "1" ]; then 592 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 593 | fi 594 | MY_EXT="${MY_EXT}" 595 | 596 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 597 | if [ "${MY_DEB}" = "1" ]; then 598 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 599 | fi 600 | MY_EXT="${!EXTENSION}" 601 | 602 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 603 | if [ "${MY_DEB}" = "1" ]; then 604 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 605 | fi 606 | MY_EXT="${MY_EXT}" 607 | 608 | else 609 | if [ "${MY_DEB}" = "1" ]; then 610 | echo "[ARG] Using all file extensions" 611 | fi 612 | MY_EXT= 613 | fi 614 | 615 | 616 | # 617 | # Decide on ignore paths 618 | # 619 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 620 | if [ "${MY_DEB}" = "1" ]; then 621 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 622 | fi 623 | MY_IGN="${MY_IGN}" 624 | 625 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 626 | if [ "${MY_DEB}" = "1" ]; then 627 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 628 | fi 629 | MY_IGN="${!IGNORE}" 630 | 631 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 632 | if [ "${MY_DEB}" = "1" ]; then 633 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 634 | fi 635 | MY_IGN="${MY_IGN}" 636 | 637 | else 638 | if [ "${MY_DEB}" = "1" ]; then 639 | echo "[ARG] Not ignoring anything" 640 | fi 641 | MY_IGN= 642 | fi 643 | 644 | 645 | # 646 | # Decide on text files (non-binary) or all files 647 | # 648 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 649 | if [ "${MY_DEB}" = "1" ]; then 650 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 651 | fi 652 | MY_TXT="${MY_TXT}" 653 | 654 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 655 | if [ "${MY_DEB}" = "1" ]; then 656 | echo "[ARG] Using config file values: --text: ${!TEXT}" 657 | fi 658 | MY_TXT="${!TEXT}" 659 | 660 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 661 | if [ "${MY_DEB}" = "1" ]; then 662 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 663 | fi 664 | MY_TXT="${MY_TXT}" 665 | 666 | else 667 | if [ "${MY_DEB}" = "1" ]; then 668 | echo "[ARG] Not narrowing down by text files" 669 | fi 670 | MY_TXT="0" 671 | fi 672 | 673 | 674 | # 675 | # Decide on file size 676 | # 677 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 678 | if [ "${MY_DEB}" = "1" ]; then 679 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 680 | fi 681 | MY_SIZ="${MY_SIZ}" 682 | 683 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 684 | if [ "${MY_DEB}" = "1" ]; then 685 | echo "[ARG] Using config file values: --size: ${!SIZE}" 686 | fi 687 | MY_SIZ="${!SIZE}" 688 | 689 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 690 | if [ "${MY_DEB}" = "1" ]; then 691 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 692 | fi 693 | MY_SIZ="${MY_SIZ}" 694 | 695 | else 696 | if [ "${MY_DEB}" = "1" ]; then 697 | echo "[ARG] Not narrowing down by size > 0 bytes" 698 | fi 699 | MY_SIZ="0" 700 | fi 701 | 702 | if [ "${MY_SIZ}" = "1" ]; then 703 | MY_SIZ="! -size 0" 704 | else 705 | MY_SIZ="" 706 | fi 707 | 708 | 709 | 710 | # 711 | # Decide on Custom string 712 | # 713 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 714 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Cmd arg --custom \"${MY_CUS}\" will take precedence over config file value". 717 | fi 718 | MY_CUS="${MY_CUS}" 719 | 720 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 721 | if [ "${MY_DEB}" = "1" ]; then 722 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 723 | fi 724 | MY_CUS="${!CUSTOM}" 725 | 726 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 727 | if [ "${MY_DEB}" = "1" ]; then 728 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 729 | fi 730 | MY_CUS="${MY_CUS}" 731 | 732 | else 733 | if [ "${MY_DEB}" = "1" ]; then 734 | echo "[ARG] No customization applied" 735 | fi 736 | MY_CUS= 737 | fi 738 | fi 739 | 740 | 741 | 742 | ############################################################ 743 | # Build command 744 | ############################################################ 745 | 746 | # 747 | # 'find' pattern for file extensions 748 | # 749 | if [ "${MY_EXT}" != "" ]; then 750 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 751 | else 752 | NAME_PATTERN="" 753 | fi 754 | 755 | # 756 | # 'find' pattern for ignores/excludes 757 | # 758 | if [ "${MY_IGN}" != "" ]; then 759 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 760 | else 761 | EXCL_PATTERN="" 762 | fi 763 | 764 | 765 | # 766 | # Fix? 767 | # 768 | if [ "${MY_FIX}" = "1" ]; then 769 | MY_CHECK="${MY_FIX_CMD}" 770 | else 771 | # 772 | # Normal check 773 | # (Apply custom command?) 774 | # 775 | if [ "${MY_CUS}" = "" ]; then 776 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 777 | else 778 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 779 | fi 780 | fi 781 | 782 | 783 | # 784 | # Show files or grep in found files? 785 | # 786 | 787 | 788 | # Be verbose? 789 | if [ "${MY_VER}" = "1" ]; then 790 | XARGS_VERBOSE="-t" 791 | else 792 | XARGS_VERBOSE="" 793 | fi 794 | 795 | # 796 | # Build command 797 | # 798 | 799 | 800 | ### Text files (list-only) 801 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 802 | if [ "${MY_SHE}" != "" ]; then 803 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 804 | else 805 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 806 | fi 807 | 808 | ### Text files (run!!!) 809 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 810 | if [ "${MY_SHE}" != "" ]; then 811 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 812 | else 813 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 814 | fi 815 | 816 | ### All files (list-only) 817 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 818 | if [ "${MY_SHE}" != "" ]; then 819 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 820 | else 821 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 822 | fi 823 | 824 | 825 | ### All files (run!!!) 826 | else 827 | if [ "${MY_SHE}" != "" ]; then 828 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 829 | else 830 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 831 | fi 832 | 833 | fi 834 | 835 | 836 | 837 | 838 | ############################################################ 839 | # Execute 840 | ############################################################ 841 | 842 | # Dry mode? 843 | if [ "${MY_DRY}" = "1" ]; then 844 | printf "%s\n" "${MY_CMD}" 845 | exit 0 846 | fi 847 | 848 | printf "\$ %s\n" "${MY_CMD}" 849 | 850 | output="$(eval "${MY_CMD}")" 851 | 852 | # If showing files only, exit normally 853 | if [ "${MY_LST}" = "1" ]; then 854 | printf "%s\n" "${output}" 855 | exit 0 856 | fi 857 | 858 | 859 | if [ "${output}" != "" ]; then 860 | printf "%s\n" "${output}" 861 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 862 | exit 1 863 | else 864 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 865 | exit 0 866 | fi 867 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker image for `file-lint` 2 | 3 | [![Tag](https://img.shields.io/github/tag/cytopia/docker-file-lint.svg)](https://github.com/cytopia/docker-file-lint/releases) 4 | [![](https://img.shields.io/badge/github-cytopia%2Fdocker--file--lint-red.svg)](https://github.com/cytopia/docker-file-lint "github.com/cytopia/docker-file-lint") 5 | [![License](https://img.shields.io/badge/license-MIT-%233DA639.svg)](https://opensource.org/licenses/MIT) 6 | 7 | [![lint](https://github.com/cytopia/docker-file-lint/workflows/lint/badge.svg)](https://github.com/cytopia/docker-file-lint/actions?query=workflow%3Alint) 8 | [![build](https://github.com/cytopia/docker-file-lint/workflows/build/badge.svg)](https://github.com/cytopia/docker-file-lint/actions?query=workflow%3Abuild) 9 | [![nightly](https://github.com/cytopia/docker-file-lint/workflows/nightly/badge.svg)](https://github.com/cytopia/docker-file-lint/actions?query=workflow%3Anightly) 10 | 11 | 12 | > #### All [#awesome-ci](https://github.com/topics/awesome-ci) Docker images 13 | > 14 | > [ansible-lint][alint-git-lnk] **•** 15 | > [ansible][ansible-git-lnk] **•** 16 | > [awesome-ci][aci-git-lnk] **•** 17 | > [bandit][bandit-git-lnk] **•** 18 | > [black][black-git-lnk] **•** 19 | > [checkmake][cm-git-lnk] **•** 20 | > [eslint][elint-git-lnk] **•** 21 | > [file-lint][flint-git-lnk] **•** 22 | > [gofmt][gfmt-git-lnk] **•** 23 | > [goimports][gimp-git-lnk] **•** 24 | > [golint][glint-git-lnk] **•** 25 | > [jsonlint][jlint-git-lnk] **•** 26 | > [kubeval][kubeval-git-lnk] **•** 27 | > [linkcheck][linkcheck-git-lnk] **•** 28 | > [mypy][mypy-git-lnk] **•** 29 | > [php-cs-fixer][pcsf-git-lnk] **•** 30 | > [phpcbf][pcbf-git-lnk] **•** 31 | > [phpcs][pcs-git-lnk] **•** 32 | > [phplint][plint-git-lnk] **•** 33 | > [pycodestyle][pycs-git-lnk] **•** 34 | > [pydocstyle][pyds-git-lnk] **•** 35 | > [pylint][pylint-git-lnk] **•** 36 | > [terraform-docs][tfdocs-git-lnk] **•** 37 | > [terragrunt-fmt][tgfmt-git-lnk] **•** 38 | > [terragrunt][tg-git-lnk] **•** 39 | > [yamlfmt][yfmt-git-lnk] **•** 40 | > [yamllint][ylint-git-lnk] 41 | 42 | View **[Dockerfiles](https://github.com/cytopia/docker-file-lint/blob/master/Dockerfiles/)** on GitHub. 43 | 44 | 45 | **Available Architectures:** `amd64`, `i386`, `arm64`, `arm/v7`, `arm/v6` 46 | 47 | Tiny Alpine-based Docker image for the very basics of CI against your code files based one [awesome-ci](https://github.com/topics/awesome-ci)[1]. 48 | 49 | [1] Original project: https://github.com/topics/awesome-ci 50 | 51 | 52 | ## :whale: Available Docker image versions 53 | 54 | [![](https://img.shields.io/docker/pulls/cytopia/file-lint.svg)](https://hub.docker.com/r/cytopia/file-lint) 55 | [![Docker](https://badgen.net/badge/icon/:latest?icon=docker&label=cytopia/file-lint)](https://hub.docker.com/r/cytopia/file-lint) 56 | 57 | #### Rolling releaess 58 | 59 | The following Docker image tags are rolling releases and are built and updated every night. 60 | 61 | [![nightly](https://github.com/cytopia/docker-file-lint/workflows/nightly/badge.svg)](https://github.com/cytopia/docker-file-lint/actions?query=workflow%3Anightly) 62 | 63 | 64 | | Docker Tag | Git Ref | file-lint | Flavour | Available Architectures | 65 | |----------------------|-----------|--------------|---------|----------------------------------------------| 66 | | `latest` | master | latest | default | `amd64`, `i386`, `arm64`, `arm/v7`, `arm/v6` | 67 | | `alpine` | master | latest | Alpine | `amd64`, `i386`, `arm64`, `arm/v7`, `arm/v6` | 68 | 69 | #### Point in time releases 70 | 71 | The following Docker image tags are built once and can be used for reproducible builds. Its version never changes so you will have to update tags in your pipelines from time to time in order to stay up-to-date. 72 | 73 | [![build](https://github.com/cytopia/docker-file-lint/workflows/build/badge.svg)](https://github.com/cytopia/docker-file-lint/actions?query=workflow%3Abuild) 74 | 75 | 76 | | Docker Tag | Git Ref | file-lint | Flavour | Available Architectures | 77 | |-----------------------|--------------|--------------|---------|----------------------------------------------| 78 | | `latest-` | tag: `` | latest | default | `amd64`, `i386`, `arm64`, `arm/v7`, `arm/v6` | 79 | | `alpine-latest-` | tag: `` | latest | Alpine | `amd64`, `i386`, `arm64`, `arm/v7`, `arm/v6` | 80 | 81 | > Where `` refers to the chosen git tag from this repository. 82 | 83 | 84 | ## :star: Features 85 | 86 | * dry run (which shows all piped unix command voodoo for learning) 87 | * project based configuration file (`awesome-ci.conf`) 88 | * check for empty files 89 | * check for files with carriage returns (`\r`) 90 | * check for files with windows newlines (`\r\n`) 91 | * check for files with nullbyte characters (`\x00`) 92 | * check for trailing newlines at eof (exactly one or multiple) 93 | * check for trailing white space 94 | * ensure files are utf8 encoded 95 | * ensure files do not contain utf8 bom (byte order mark: `U+FEFF`) 96 | * allows for automatic fixing (most commands) 97 | * allows for find-grained control 98 | - check files by specific extension(s) only 99 | - check files by specific shebang only 100 | - check binary or text-files only 101 | 102 | ## :wrench: Tools 103 | | Type | Tool | Fixable | Description | 104 | |------|------|---------|-------------| 105 | | File | [file-cr](data/file-cr) | ✓ | Scan files and check if they contain CR (Carriage Return only). | 106 | | File | [file-crlf](data/file-crlf) | ✓ | Scan files and check if they contain CRLF (Windows Line Feeds). | 107 | | File | [file-empty](data/file-empty) | | Scan files and check if they are empty (0 bytes). | 108 | | File | [file-nullbyte](data/file-nullbyte) | ✓ | Scan files and check if they contain a null-byte character (`\x00)`. | 109 | | File | [file-trailing-newline](data/file-trailing-newline) | ✓ | Scan files and check if they contain a trailing newline. | 110 | | File | [file-trailing-single-newline](data/file-trailing-single-newline) | ✓ | Scan files and check if they contain exactly one trailing newline. | 111 | | File | [file-trailing-space](data/file-trailing-space) | ✓ | Scan files and check if they contain trailing whitespaces. | 112 | | File | [file-utf8](data/file-utf8) | ✓ | Scan files and check if they have a non UTF-8 encoding. | 113 | | File | [file-utf8-bom](data/file-utf8-bom) | ✓ | Scan files and check if they contain BOM (Byte Order Mark): `U+FEFF`. | 114 | | Git | [git-conflicts](data/git-conflicts) | | Scan files and check if they contain git conflicts. | 115 | 116 | > Tools extracted from https://github.com/cytopia/awesome-ci 117 | 118 | 119 | 120 | ## :open_file_folder: Docker mounts 121 | 122 | The working directory inside the Docker container is **`/data/`** and should be mounted locally. 123 | 124 | 125 | ## :computer: Usage 126 | 127 | ### General 128 | ```bash 129 | $ docker run --rm -v $(pwd):/data cytopia/file-lint 130 | 131 | ################################################################################ 132 | # cytopia/file-lint # 133 | # (awesome-ci) # 134 | ################################################################################ 135 | # # 136 | # # 137 | # Usage: # 138 | # -----------------------------------------------------------------------------# 139 | # docker run --rm cytopia/file-lint --help # 140 | # docker run --rm cytopia/file-lint --help # 141 | # docker run --rm cytopia/file-lint --info # 142 | # docker run --rm cytopia/file-lint --version # 143 | # # 144 | # # 145 | # Available tools: # 146 | # -----------------------------------------------------------------------------# 147 | # file-empty Scans if files are empty # 148 | # file-cr Scans if files contain carriage returns (\r) # 149 | # file-crlf Scans if files contain win line feeds (\r\n) # 150 | # file-nullbyte Scans if files contain nullbyte chars (\x00) # 151 | # file-trailing-newline Scans if files contain trailing newline(s) # 152 | # file-trailing-single-newline Scans if files contain single trailing newline # 153 | # file-trailing-space Scans if files contain trailing whitespace # 154 | # file-utf8 Scans if files are utf8 encoded # 155 | # file-utf8-bom Scans if files contain byte order mark # 156 | # git-conflicts Scans if files contain git conflicts # 157 | # # 158 | # # 159 | # Example: # 160 | # -----------------------------------------------------------------------------# 161 | # docker run --rm -v $(pwd):/data cytopia/file-lint \ # 162 | # lf-crlf --ignore ".git/,.github/" --path . # 163 | # # 164 | ################################################################################ 165 | ``` 166 | 167 | ### Tool usage 168 | The following help screen is taken from `file-crlf`. All other tools have the exact same functionality. 169 | ``` 170 | $ docker run --rm cytopia/file-lint file-crlf --help 171 | 172 | Usage: file-crlf [--text] [--size] [--shebang ] [--extension "tpl,htm,html,php,..."] [--ignore "dir1,dir2"] [--config "conf"] [--confpre "FILE_CRLF_"] [--fix] [--verbose] [--debug] [--dry] [--list] --path 173 | file-crlf --info 174 | file-crlf --help 175 | file-crlf --version 176 | 177 | Scans recursively for files containing CRLF (Windows Line Feeds). 178 | Will return 1 on occurance, otherwise 0. 179 | 180 | Required arguments: 181 | 182 | --path Specify directory where to scan. 183 | 184 | 185 | Optional run arguments: 186 | --fix Fixable :-) 187 | Fix the problems for the specified files. 188 | Note, all other options below also apply 189 | 190 | --text Limit search to text files only (non-binary). 191 | Can be narrowed further with '--extension' 192 | 193 | --size Limit search to files which are not empty (bigger than 0 bytes). 194 | 195 | --shebang Only find files (shell scripts) with this specific shebang. 196 | It is useful to combine this with --text and --size for faster searches. 197 | Use with --dry to see how this search command is generated. 198 | Example: 199 | --shebang bash 200 | --shebang php 201 | --shebang sh 202 | 203 | --extension Only find files matching those extensions. 204 | Comma separated list of file extensions. 205 | Only find files matching those extensions. 206 | Defaults to all files if not specified or empty. 207 | Example: 208 | --extension "html,php,inc" 209 | --extension php 210 | 211 | --ignore Comma separated list of ignore paths. 212 | Directories must be specified from the starting location of --path. 213 | Example: 214 | ignore 'foor/bar' folder inside '/var/www' path: 215 | --path /var/www --ignore foo/bar 216 | 217 | --config Load configuration file. 218 | File must contain the following directives: 219 | FILE_CRLF_EXTENSION="" # comma separated 220 | FILE_CRLF_IGNORE="" # comma separated 221 | FILE_CRLF_TEXT=0|1 # 0 or 1 222 | Note that cmd arguments take precedence over 223 | config file settings. 224 | 225 | --confpre Set custom configuration directive prefix. 226 | Current default ist: 'FILE_CRLF_'. 227 | This is useful, when you want to define different defaults 228 | per check via configuration file. 229 | 230 | --verbose Be verbose and print commands and files being checked. 231 | 232 | 233 | --debug Print system messages. 234 | 235 | 236 | Optional training arguments: 237 | --dry Don't do anything, just display the commands. 238 | 239 | --list Instead of searching inside the files, just display the filenames 240 | that would be found by --path, --extension and --ignore 241 | 242 | 243 | System arguments: 244 | --info Show versions of required commands (useful for bugreports). 245 | --help Show help screen. 246 | --version Show version information. 247 | 248 | 249 | file-crlf is part of the awesome-ci collection. 250 | https://github.com/cytopia/awesome-ci 251 | ``` 252 | 253 | ### Configuration file 254 | You can also add a configuration file named `awesome-ci.conf` to your project to configure it to your likings. 255 | ```bash 256 | # 257 | # Awesome-ci configuration file 258 | # 259 | # Each tool will have its own config section 260 | # which all behave in the same way: 261 | # 262 | # 263 | # 1. File extensions 264 | # ------------------ 265 | # Comma separated list of file extensions 266 | # to narrow down the files to check. 267 | # _EXTENSION="" 268 | # _EXTENSION="tpl,html" 269 | # 270 | # 2. Ignored paths 271 | # ---------------- 272 | # Comma separated list of file paths 273 | # to narrow down the files to check. 274 | # Note that those paths must start at the 275 | # path where --path starts. 276 | # _IGNORE="" 277 | # _IGNORE="tmp/log,tmp/run" 278 | # 279 | # 3. Text files 280 | # ------------- 281 | # 0 or 1 to specify whether to work on text files 282 | # only. 283 | # _TEXT=0 284 | # _TEXT=1 285 | 286 | 287 | 288 | 289 | # 290 | # File checkers 291 | # 292 | # file-cr 293 | FILE_CR_EXTENSION="" 294 | FILE_CR_IGNORE=".git,*.svn" 295 | FILE_CR_TEXT=1 296 | FILE_CR_SIZE=1 297 | 298 | # file-crlf 299 | FILE_CRLF_EXTENSION="" 300 | FILE_CRLF_IGNORE=".git,*.svn" 301 | FILE_CRLF_TEXT=1 302 | FILE_CRLF_SIZE=1 303 | 304 | # file-empty 305 | FILE_EMPTY_EXTENSION="" 306 | FILE_EMPTY_IGNORE=".git,*.svn" 307 | FILE_EMPTY_TEXT=0 308 | FILE_EMPTY_SIZE=0 309 | 310 | # file-nullbyte 311 | FILE_NULLBYTE_EXTENSION="" 312 | FILE_NULLBYTE_IGNORE=".git,*.svn,*.pyc" 313 | FILE_NULLBYTE_TEXT=1 314 | FILE_NULLBYTE_SIZE=1 315 | 316 | # file-trailing-newline 317 | FILE_TRAILING_NEWLINE_EXTENSION="" 318 | FILE_TRAILING_NEWLINE_IGNORE=".git,*.svn" 319 | FILE_TRAILING_NEWLINE_TEXT=1 320 | FILE_TRAILING_NEWLINE_SIZE=1 321 | 322 | # file-trailing-single-newline 323 | FILE_TRAILING_SINGLE_NEWLINE_EXTENSION="" 324 | FILE_TRAILING_SINGLE_NEWLINE_IGNORE=".git,*.svn" 325 | FILE_TRAILING_SINGLE_NEWLINE_TEXT=1 326 | FILE_TRAILING_SINGLE_NEWLINE_SIZE=1 327 | 328 | # file-trailing-space 329 | FILE_TRAILING_SPACE_EXTENSION="" 330 | FILE_TRAILING_SPACE_IGNORE=".git,*.svn" 331 | FILE_TRAILING_SPACE_TEXT=1 332 | FILE_TRAILING_SPACE_SIZE=1 333 | 334 | # file-utf8 335 | FILE_UTF8_EXTENSION="" 336 | FILE_UTF8_IGNORE=".git,*.svn" 337 | FILE_UTF8_TEXT=1 338 | FILE_UTF8_SIZE=1 339 | 340 | # file-utf8-bom 341 | FILE_UTF8_BOM_EXTENSION="" 342 | FILE_UTF8_BOM_IGNORE=".git,*.svn" 343 | FILE_UTF8_BOM_TEXT=1 344 | FILE_UTF8_BOM_SIZE=1 345 | 346 | # git-conflicts 347 | GIT_CONFLICTS_EXTENSION="" 348 | GIT_CONFLICTS_IGNORE=".git,*.svn" 349 | GIT_CONFLICTS_TEXT=1 350 | GIT_CONFLICTS_SIZE=1 351 | ``` 352 | 353 | ### Example Makefile 354 | ```make 355 | ifneq (,) 356 | .error This Makefile requires GNU Make. 357 | endif 358 | 359 | .PHONY: lint _lint-cr _lint-crlf _lint-trailing-single-newline _lint-trailing-space _lint-utf8 _lint-utf8-bom _lint-git-conflicts 360 | 361 | FL_VERSION = latest 362 | FL_IGNORE_PATHS = .git/,.github/ 363 | 364 | lint: 365 | @$(MAKE) --no-print-directory _lint-cr 366 | @$(MAKE) --no-print-directory _lint-crlf 367 | @$(MAKE) --no-print-directory _lint-trailing-single-newline 368 | @$(MAKE) --no-print-directory _lint-trailing-space 369 | @$(MAKE) --no-print-directory _lint-utf8 370 | @$(MAKE) --no-print-directory _lint-utf8-bom 371 | @$(MAKE) --no-print-directory _lint-git-conflicts 372 | 373 | _lint-cr: 374 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-cr --text --ignore '$(FL_IGNORE_PATHS)' --path . 375 | 376 | _lint-crlf: 377 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-crlf --text --ignore '$(FL_IGNORE_PATHS)' --path . 378 | 379 | _lint-trailing-single-newline: 380 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-trailing-single-newline --text --ignore '$(FL_IGNORE_PATHS)' --path . 381 | 382 | _lint-trailing-space: 383 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-trailing-space --text --ignore '$(FL_IGNORE_PATHS)' --path . 384 | 385 | _lint-utf8: 386 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8 --text --ignore '$(FL_IGNORE_PATHS)' --path . 387 | 388 | _lint-utf8-bom: 389 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8-bom --text --ignore '$(FL_IGNORE_PATHS)' --path . 390 | 391 | _lint-git-conflicts: 392 | @docker run --rm -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) git-conflicts --text --ignore '$(FL_IGNORE_PATHS)' --path . 393 | 394 | ``` 395 | 396 | 397 | ## :arrows_counterclockwise: Related [#awesome-ci](https://github.com/topics/awesome-ci) projects 398 | 399 | ### Docker images 400 | 401 | Save yourself from installing lot's of dependencies and pick a dockerized version of your favourite 402 | linter below for reproducible local or remote CI tests: 403 | 404 | | GitHub | DockerHub | Type | Description | 405 | |--------|-----------|------|-------------| 406 | | [awesome-ci][aci-git-lnk] | [![aci-hub-img]][aci-hub-lnk] | Basic | Tools for git, file and static source code analysis | 407 | | [file-lint][flint-git-lnk] | [![flint-hub-img]][flint-hub-lnk] | Basic | Baisc source code analysis | 408 | | [linkcheck][linkcheck-git-lnk] | [![linkcheck-hub-img]][flint-hub-lnk] | Basic | Search for URLs in files and validate their HTTP status code | 409 | | [ansible][ansible-git-lnk] | [![ansible-hub-img]][ansible-hub-lnk] | Ansible | Multiple versions and flavours of Ansible | 410 | | [ansible-lint][alint-git-lnk] | [![alint-hub-img]][alint-hub-lnk] | Ansible | Lint Ansible | 411 | | [gofmt][gfmt-git-lnk] | [![gfmt-hub-img]][gfmt-hub-lnk] | Go | Format Go source code **[1]** | 412 | | [goimports][gimp-git-lnk] | [![gimp-hub-img]][gimp-hub-lnk] | Go | Format Go source code **[1]** | 413 | | [golint][glint-git-lnk] | [![glint-hub-img]][glint-hub-lnk] | Go | Lint Go code | 414 | | [eslint][elint-git-lnk] | [![elint-hub-img]][elint-hub-lnk] | Javascript | Lint Javascript code | 415 | | [jsonlint][jlint-git-lnk] | [![jlint-hub-img]][jlint-hub-lnk] | JSON | Lint JSON files **[1]** | 416 | | [kubeval][kubeval-git-lnk] | [![kubeval-hub-img]][kubeval-hub-lnk] | K8s | Lint Kubernetes files | 417 | | [checkmake][cm-git-lnk] | [![cm-hub-img]][cm-hub-lnk] | Make | Lint Makefiles | 418 | | [phpcbf][pcbf-git-lnk] | [![pcbf-hub-img]][pcbf-hub-lnk] | PHP | PHP Code Beautifier and Fixer | 419 | | [phpcs][pcs-git-lnk] | [![pcs-hub-img]][pcs-hub-lnk] | PHP | PHP Code Sniffer | 420 | | [phplint][plint-git-lnk] | [![plint-hub-img]][plint-hub-lnk] | PHP | PHP Code Linter **[1]** | 421 | | [php-cs-fixer][pcsf-git-lnk] | [![pcsf-hub-img]][pcsf-hub-lnk] | PHP | PHP Coding Standards Fixer | 422 | | [bandit][bandit-git-lnk] | [![bandit-hub-img]][bandit-hub-lnk] | Python | A security linter from PyCQA 423 | | [black][black-git-lnk] | [![black-hub-img]][black-hub-lnk] | Python | The uncompromising Python code formatter | 424 | | [mypy][mypy-git-lnk] | [![mypy-hub-img]][mypy-hub-lnk] | Python | Static source code analysis | 425 | | [pycodestyle][pycs-git-lnk] | [![pycs-hub-img]][pycs-hub-lnk] | Python | Python style guide checker | 426 | | [pydocstyle][pyds-git-lnk] | [![pyds-hub-img]][pyds-hub-lnk] | Python | Python docstyle checker | 427 | | [pylint][pylint-git-lnk] | [![pylint-hub-img]][pylint-hub-lnk] | Python | Python source code, bug and quality checker | 428 | | [terraform-docs][tfdocs-git-lnk] | [![tfdocs-hub-img]][tfdocs-hub-lnk] | Terraform | Terraform doc generator (TF 0.12 ready) **[1]** | 429 | | [terragrunt][tg-git-lnk] | [![tg-hub-img]][tg-hub-lnk] | Terraform | Terragrunt and Terraform | 430 | | [terragrunt-fmt][tgfmt-git-lnk] | [![tgfmt-hub-img]][tgfmt-hub-lnk] | Terraform | `terraform fmt` for Terragrunt files **[1]** | 431 | | [yamlfmt][yfmt-git-lnk] | [![yfmt-hub-img]][yfmt-hub-lnk] | Yaml | Format Yaml files **[1]** | 432 | | [yamllint][ylint-git-lnk] | [![ylint-hub-img]][ylint-hub-lnk] | Yaml | Lint Yaml files | 433 | 434 | > **[1]** Uses a shell wrapper to add **enhanced functionality** not available by original project. 435 | 436 | [aci-git-lnk]: https://github.com/cytopia/awesome-ci 437 | [aci-hub-img]: https://img.shields.io/docker/pulls/cytopia/awesome-ci.svg 438 | [aci-hub-lnk]: https://hub.docker.com/r/cytopia/awesome-ci 439 | 440 | [flint-git-lnk]: https://github.com/cytopia/docker-file-lint 441 | [flint-hub-img]: https://img.shields.io/docker/pulls/cytopia/file-lint.svg 442 | [flint-hub-lnk]: https://hub.docker.com/r/cytopia/file-lint 443 | 444 | [linkcheck-git-lnk]: https://github.com/cytopia/docker-linkcheck 445 | [linkcheck-hub-img]: https://img.shields.io/docker/pulls/cytopia/linkcheck.svg 446 | [linkcheck-hub-lnk]: https://hub.docker.com/r/cytopia/linkcheck 447 | 448 | [jlint-git-lnk]: https://github.com/cytopia/docker-jsonlint 449 | [jlint-hub-img]: https://img.shields.io/docker/pulls/cytopia/jsonlint.svg 450 | [jlint-hub-lnk]: https://hub.docker.com/r/cytopia/jsonlint 451 | 452 | [ansible-git-lnk]: https://github.com/cytopia/docker-ansible 453 | [ansible-hub-img]: https://img.shields.io/docker/pulls/cytopia/ansible.svg 454 | [ansible-hub-lnk]: https://hub.docker.com/r/cytopia/ansible 455 | 456 | [alint-git-lnk]: https://github.com/cytopia/docker-ansible-lint 457 | [alint-hub-img]: https://img.shields.io/docker/pulls/cytopia/ansible-lint.svg 458 | [alint-hub-lnk]: https://hub.docker.com/r/cytopia/ansible-lint 459 | 460 | [kubeval-git-lnk]: https://github.com/cytopia/docker-kubeval 461 | [kubeval-hub-img]: https://img.shields.io/docker/pulls/cytopia/kubeval.svg 462 | [kubeval-hub-lnk]: https://hub.docker.com/r/cytopia/kubeval 463 | 464 | [gfmt-git-lnk]: https://github.com/cytopia/docker-gofmt 465 | [gfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/gofmt.svg 466 | [gfmt-hub-lnk]: https://hub.docker.com/r/cytopia/gofmt 467 | 468 | [gimp-git-lnk]: https://github.com/cytopia/docker-goimports 469 | [gimp-hub-img]: https://img.shields.io/docker/pulls/cytopia/goimports.svg 470 | [gimp-hub-lnk]: https://hub.docker.com/r/cytopia/goimports 471 | 472 | [glint-git-lnk]: https://github.com/cytopia/docker-golint 473 | [glint-hub-img]: https://img.shields.io/docker/pulls/cytopia/golint.svg 474 | [glint-hub-lnk]: https://hub.docker.com/r/cytopia/golint 475 | 476 | [elint-git-lnk]: https://github.com/cytopia/docker-eslint 477 | [elint-hub-img]: https://img.shields.io/docker/pulls/cytopia/eslint.svg 478 | [elint-hub-lnk]: https://hub.docker.com/r/cytopia/eslint 479 | 480 | [cm-git-lnk]: https://github.com/cytopia/docker-checkmake 481 | [cm-hub-img]: https://img.shields.io/docker/pulls/cytopia/checkmake.svg 482 | [cm-hub-lnk]: https://hub.docker.com/r/cytopia/checkmake 483 | 484 | [pcbf-git-lnk]: https://github.com/cytopia/docker-phpcbf 485 | [pcbf-hub-img]: https://img.shields.io/docker/pulls/cytopia/phpcbf.svg 486 | [pcbf-hub-lnk]: https://hub.docker.com/r/cytopia/phpcbf 487 | 488 | [pcs-git-lnk]: https://github.com/cytopia/docker-phpcs 489 | [pcs-hub-img]: https://img.shields.io/docker/pulls/cytopia/phpcs.svg 490 | [pcs-hub-lnk]: https://hub.docker.com/r/cytopia/phpcs 491 | 492 | [plint-git-lnk]: https://github.com/cytopia/docker-phplint 493 | [plint-hub-img]: https://img.shields.io/docker/pulls/cytopia/phplint.svg 494 | [plint-hub-lnk]: https://hub.docker.com/r/cytopia/phplint 495 | 496 | [pcsf-git-lnk]: https://github.com/cytopia/docker-php-cs-fixer 497 | [pcsf-hub-img]: https://img.shields.io/docker/pulls/cytopia/php-cs-fixer.svg 498 | [pcsf-hub-lnk]: https://hub.docker.com/r/cytopia/php-cs-fixer 499 | 500 | [bandit-git-lnk]: https://github.com/cytopia/docker-bandit 501 | [bandit-hub-img]: https://img.shields.io/docker/pulls/cytopia/bandit.svg 502 | [bandit-hub-lnk]: https://hub.docker.com/r/cytopia/bandit 503 | 504 | [black-git-lnk]: https://github.com/cytopia/docker-black 505 | [black-hub-img]: https://img.shields.io/docker/pulls/cytopia/black.svg 506 | [black-hub-lnk]: https://hub.docker.com/r/cytopia/black 507 | 508 | [mypy-git-lnk]: https://github.com/cytopia/docker-mypy 509 | [mypy-hub-img]: https://img.shields.io/docker/pulls/cytopia/mypy.svg 510 | [mypy-hub-lnk]: https://hub.docker.com/r/cytopia/mypy 511 | 512 | [pycs-git-lnk]: https://github.com/cytopia/docker-pycodestyle 513 | [pycs-hub-img]: https://img.shields.io/docker/pulls/cytopia/pycodestyle.svg 514 | [pycs-hub-lnk]: https://hub.docker.com/r/cytopia/pycodestyle 515 | 516 | [pyds-git-lnk]: https://github.com/cytopia/docker-pydocstyle 517 | [pyds-hub-img]: https://img.shields.io/docker/pulls/cytopia/pydocstyle.svg 518 | [pyds-hub-lnk]: https://hub.docker.com/r/cytopia/pydocstyle 519 | 520 | [pylint-git-lnk]: https://github.com/cytopia/docker-pylint 521 | [pylint-hub-img]: https://img.shields.io/docker/pulls/cytopia/pylint.svg 522 | [pylint-hub-lnk]: https://hub.docker.com/r/cytopia/pylint 523 | 524 | [tfdocs-git-lnk]: https://github.com/cytopia/docker-terraform-docs 525 | [tfdocs-hub-img]: https://img.shields.io/docker/pulls/cytopia/terraform-docs.svg 526 | [tfdocs-hub-lnk]: https://hub.docker.com/r/cytopia/terraform-docs 527 | 528 | [tg-git-lnk]: https://github.com/cytopia/docker-terragrunt 529 | [tg-hub-img]: https://img.shields.io/docker/pulls/cytopia/terragrunt.svg 530 | [tg-hub-lnk]: https://hub.docker.com/r/cytopia/terragrunt 531 | 532 | [tgfmt-git-lnk]: https://github.com/cytopia/docker-terragrunt-fmt 533 | [tgfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/terragrunt-fmt.svg 534 | [tgfmt-hub-lnk]: https://hub.docker.com/r/cytopia/terragrunt-fmt 535 | 536 | [yfmt-git-lnk]: https://github.com/cytopia/docker-yamlfmt 537 | [yfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/yamlfmt.svg 538 | [yfmt-hub-lnk]: https://hub.docker.com/r/cytopia/yamlfmt 539 | 540 | [ylint-git-lnk]: https://github.com/cytopia/docker-yamllint 541 | [ylint-hub-img]: https://img.shields.io/docker/pulls/cytopia/yamllint.svg 542 | [ylint-hub-lnk]: https://hub.docker.com/r/cytopia/yamllint 543 | 544 | 545 | ### Makefiles 546 | 547 | Visit **[cytopia/makefiles](https://github.com/cytopia/makefiles)** for dependency-less, seamless project integration and minimum required best-practice code linting for CI. 548 | The provided Makefiles will only require GNU Make and Docker itself removing the need to install anything else. 549 | 550 | 551 | ## :page_facing_up: License 552 | 553 | 554 | **[MIT License](LICENSE)** 555 | 556 | Copyright (c) 2019 [cytopia](https://github.com/cytopia) 557 | --------------------------------------------------------------------------------