diff --git a/.automation/test/clang_format/README.md b/.automation/test/clang_format/README.md new file mode 100644 index 00000000..e66d8a86 --- /dev/null +++ b/.automation/test/clang_format/README.md @@ -0,0 +1,19 @@ +# CPP Test Cases + +This folder holds the test cases for **CPP**. + +## Additional Docs + +No Additional information is needed for this test case. + +## Good Test Cases + +The test cases denoted: `LANGUAGE_good_FILE.EXTENSION` are all valid, and should pass successfully when linted. + +- **Note:** They are linted utilizing the default linter rules. + +## Bad Test Cases + +The test cases denoted: `LANGUAGE_bad_FILE.EXTENSION` are **NOT** valid, and should trigger errors when linted. + +- **Note:** They are linted utilizing the default linter rules. diff --git a/.automation/test/clang_format/clang_bad_01.cpp b/.automation/test/clang_format/clang_bad_01.cpp new file mode 100644 index 00000000..e18feac3 --- /dev/null +++ b/.automation/test/clang_format/clang_bad_01.cpp @@ -0,0 +1,14 @@ +#include +#include +using namespace std; + +int main() { + // Create and open a text file + ofstream MyFile("filename.txt"); + + // Write to the file + MyFile << "Files can be tricky, but it is fun enough!"; + + // Close the file + //MyFile.close(); +} diff --git a/.automation/test/clang_format/clang_good_01.cpp b/.automation/test/clang_format/clang_good_01.cpp new file mode 100644 index 00000000..6631c92c --- /dev/null +++ b/.automation/test/clang_format/clang_good_01.cpp @@ -0,0 +1,16 @@ +// Copyright 2021 GitHub + +#include +#include +using std::string; + +int main() { + // Create and open a text file + ofstream MyFile("filename.txt"); + + // Write to the file + MyFile << "Files can be tricky, but it is fun enough!"; + + // Close the file + MyFile.close(); +} diff --git a/.automation/test/cpp/README.md b/.automation/test/cpp/README.md index e66d8a86..7ef6604f 100644 --- a/.automation/test/cpp/README.md +++ b/.automation/test/cpp/README.md @@ -1,6 +1,6 @@ -# CPP Test Cases +# Clang Test Cases -This folder holds the test cases for **CPP**. +This folder holds the test cases for **Clang**. ## Additional Docs diff --git a/.automation/test/cpp/cpp_good_01.cpp b/.automation/test/cpp/cpp_good_01.cpp index c2e8ade0..6631c92c 100644 --- a/.automation/test/cpp/cpp_good_01.cpp +++ b/.automation/test/cpp/cpp_good_01.cpp @@ -1,7 +1,7 @@ // Copyright 2021 GitHub -#include #include +#include using std::string; int main() { diff --git a/Dockerfile b/Dockerfile index c424d808..064fb56c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -295,6 +295,44 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repo && find /node_modules/ -type f -name '*.txt' -exec rm {} + \ && find /usr/ -type f -name '*.md' -exec rm {} + +################################################################################ +# Build the clang binary ####################################################### +################################################################################ +FROM alpine:3.14.0 as clang-format-build + +###################### +# Build dependencies # +###################### +RUN apk add --no-cache \ + build-base \ + clang \ + cmake \ + git \ + ninja \ + python3 + +############################################################# +# Pass `--build-arg LLVM_TAG=master` for latest llvm commit # +############################################################# +ARG LLVM_TAG +ENV LLVM_TAG llvmorg-12.0.1 + +###################### +# Download and setup # +###################### +WORKDIR /tmp +RUN git clone --branch ${LLVM_TAG} --depth 1 https://github.com/llvm/llvm-project.git +WORKDIR /tmp/llvm-project + +######### +# Build # +######### +WORKDIR /tmp/llvm-project/llvm/build +RUN cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_BUILD_STATIC=ON \ + -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ .. \ + && ninja clang-format + ################################################################################ # Grab small clean image ####################################################### ################################################################################ @@ -377,6 +415,7 @@ COPY --from=base_image /lib/ /lib/ COPY --from=base_image /bin/ /bin/ COPY --from=base_image /node_modules/ /node_modules/ COPY --from=base_image /home/r-library /home/r-library +COPY --from=clang-format-build /tmp/llvm-project/llvm/build/bin/clang-format /usr/bin/clang-format ######################################## # Add node packages to path and dotnet # diff --git a/Dockerfile-slim b/Dockerfile-slim index ad03dfba..d19d3ffc 100644 --- a/Dockerfile-slim +++ b/Dockerfile-slim @@ -233,6 +233,44 @@ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community/" >> /etc/apk/repo && find /node_modules/ -type f -name '*.txt' -exec rm {} + \ && find /usr/ -type f -name '*.md' -exec rm {} + +################################################################################ +# Build the clang binary ####################################################### +################################################################################ +FROM alpine:3.14.0 as clang-format-build + +###################### +# Build dependencies # +###################### +RUN apk add --no-cache \ + build-base \ + clang \ + cmake \ + git \ + ninja \ + python3 + +############################################################# +# Pass `--build-arg LLVM_TAG=master` for latest llvm commit # +############################################################# +ARG LLVM_TAG +ENV LLVM_TAG llvmorg-12.0.1 + +###################### +# Download and setup # +###################### +WORKDIR /tmp +RUN git clone --branch ${LLVM_TAG} --depth 1 https://github.com/llvm/llvm-project.git +WORKDIR /tmp/llvm-project + +######### +# Build # +######### +WORKDIR /tmp/llvm-project/llvm/build +RUN cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DLLVM_BUILD_STATIC=ON \ + -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ .. \ + && ninja clang-format + ################################################################################ # Grab small clean image ####################################################### ################################################################################ @@ -313,6 +351,7 @@ COPY --from=base_image /lib/ /lib/ COPY --from=base_image /bin/ /bin/ COPY --from=base_image /node_modules/ /node_modules/ COPY --from=base_image /home/r-library /home/r-library +COPY --from=clang-format-build /tmp/llvm-project/llvm/build/bin/clang-format /usr/bin/clang-format ######################################## # Add node packages to path and dotnet # diff --git a/README.md b/README.md index c93ecc06..b38322de 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ Developers on **GitHub** can call the **GitHub Action** to lint their code base | **Ansible** | [ansible-lint](https://github.com/ansible/ansible-lint) | | **Azure Resource Manager (ARM)** | [arm-ttk](https://github.com/azure/arm-ttk) | | **AWS CloudFormation templates** | [cfn-lint](https://github.com/aws-cloudformation/cfn-python-lint/) | -| **C++** | [cpp-lint](https://github.com/cpplint/cpplint) | -| **C#** | [dotnet-format](https://github.com/dotnet/format) | +| **C++** | [cpp-lint](https://github.com/cpplint/cpplint) / [clang](https://github.com/llvm/llvm-project.git) | +| **C#** | [dotnet-format](https://github.com/dotnet/format) / [clang](https://github.com/llvm/llvm-project.git) | | **CSS** | [stylelint](https://stylelint.io/) | | **Clojure** | [clj-kondo](https://github.com/borkdude/clj-kondo) | | **CoffeeScript** | [coffeelint](https://coffeelint.github.io/) | @@ -308,7 +308,7 @@ But if you wish to select or exclude specific linters, we give you full control | **SSL_CERT_SECRET** | `none` | SSL cert to add to the **Super-Linter** trust store. This is needed for users on `self-hosted` runners or need to inject the cert for security standards (ex. ${{ secrets.SSL_CERT }}) | | **SQL_CONFIG_FILE** | `.sql-config.json` | Filename for [SQL-Lint configuration](https://sql-lint.readthedocs.io/en/latest/files/configuration.html) (ex: `sql-config.json` , `.config.json`) | | **TERRAFORM_CONFIG_FILE** | `.tflint.hcl` | Filename for [tfLint configuration](https://github.com/terraform-linters/tflint) (ex: `.tflint.hcl`) | -| **TERRAFORM_TERRASCAN_CONFIG_FILE**| `terrascan.toml` | Filename for [terrascan configuration](https://github.com/accurics/terrascan) (ex: `terrascan.toml`) | +| **TERRAFORM_TERRASCAN_CONFIG_FILE**| `terrascan.toml` | Filename for [terrascan configuration](https://github.com/accurics/terrascan) (ex: `terrascan.toml`) | | **TYPESCRIPT_ES_CONFIG_FILE** | `.eslintrc.yml` | Filename for [eslint configuration](https://eslint.org/docs/user-guide/configuring#configuration-file-formats) (ex: `.eslintrc.yml`, `.eslintrc.json`) | | **USE_FIND_ALGORITHM** | `false` | By default, we use `git diff` to find all files in the workspace and what has been updated, this would enable the Linux `find` method instead to find all files to lint | | **VALIDATE_ALL_CODEBASE** | `true` | Will parse the entire repository and find all files to validate across all types. **NOTE:** When set to `false`, only **new** or **edited** files will be parsed for validation. | @@ -317,6 +317,7 @@ But if you wish to select or exclude specific linters, we give you full control | **VALIDATE_BASH** | `true` | Flag to enable or disable the linting process of the Bash language. | | **VALIDATE_BASH_EXEC** | `true` | Flag to enable or disable the linting process of the Bash language to validate if file is stored as executable. | | **VALIDATE_CPP** | `true` | Flag to enable or disable the linting process of the C++ language. | +| **VALIDATE_CLANG_FORMAT** | `true` | Flag to enable or disable the linting process of the C++/C language with clang. | | **VALIDATE_CLOJURE** | `true` | Flag to enable or disable the linting process of the Clojure language. | | **VALIDATE_CLOUDFORMATION** | `true` | Flag to enable or disable the linting process of the AWS Cloud Formation language. | | **VALIDATE_COFFEESCRIPT** | `true` | Flag to enable or disable the linting process of the Coffeescript language. | diff --git a/lib/functions/buildFileList.sh b/lib/functions/buildFileList.sh index 521ca15d..c10061df 100755 --- a/lib/functions/buildFileList.sh +++ b/lib/functions/buildFileList.sh @@ -350,6 +350,8 @@ function BuildFileList() { # Append the file to the array # ################################ FILE_ARRAY_CPP+=("${FILE}") + FILE_ARRAY_CLANG_FORMAT+=("${FILE}") + ######################## # Get the COFFEE files # ######################## diff --git a/lib/linter.sh b/lib/linter.sh index 32f7c281..82f479dc 100755 --- a/lib/linter.sh +++ b/lib/linter.sh @@ -193,14 +193,17 @@ fi ################## # Language array # ################## -LANGUAGE_ARRAY=('ANSIBLE' 'ARM' 'BASH' 'BASH_EXEC' 'CLOUDFORMATION' 'CLOJURE' 'COFFEESCRIPT' 'CPP' 'CSHARP' 'CSS' - 'DART' 'DOCKERFILE' 'DOCKERFILE_HADOLINT' 'EDITORCONFIG' 'ENV' 'GHERKIN' 'GO' 'GROOVY' 'HTML' - 'JAVA' 'JAVASCRIPT_ES' "${JAVASCRIPT_STYLE_NAME}" 'JSCPD' 'JSON' 'JSONC' 'JSX' 'KUBERNETES_KUBEVAL' 'KOTLIN' 'LATEX' 'LUA' 'MARKDOWN' - 'OPENAPI' 'PERL' 'PHP_BUILTIN' 'PHP_PHPCS' 'PHP_PHPSTAN' 'PHP_PSALM' 'POWERSHELL' - 'PROTOBUF' 'PYTHON_BLACK' 'PYTHON_PYLINT' 'PYTHON_FLAKE8' 'PYTHON_ISORT' 'PYTHON_MYPY' - 'R' 'RAKU' 'RUBY' 'RUST_2015' 'RUST_2018' 'RUST_CLIPPY' - 'SHELL_SHFMT' 'SNAKEMAKE_LINT' 'SNAKEMAKE_SNAKEFMT' 'STATES' 'SQL' - 'TEKTON' 'TERRAFORM' 'TERRAFORM_TERRASCAN' 'TERRAGRUNT' 'TSX' 'TYPESCRIPT_ES' 'TYPESCRIPT_STANDARD' 'XML' 'YAML') +LANGUAGE_ARRAY=('ANSIBLE' 'ARM' 'BASH' 'BASH_EXEC' 'CLANG_FORMAT' + 'CLOUDFORMATION' 'CLOJURE' 'COFFEESCRIPT' 'CPP' 'CSHARP' 'CSS' 'DART' + 'DOCKERFILE' 'DOCKERFILE_HADOLINT' 'EDITORCONFIG' 'ENV' 'GHERKIN' 'GO' + 'GROOVY' 'HTML' 'JAVA' 'JAVASCRIPT_ES' "${JAVASCRIPT_STYLE_NAME}" 'JSCPD' + 'JSON' 'JSONC' 'JSX' 'KUBERNETES_KUBEVAL' 'KOTLIN' 'LATEX' 'LUA' 'MARKDOWN' + 'OPENAPI' 'PERL' 'PHP_BUILTIN' 'PHP_PHPCS' 'PHP_PHPSTAN' 'PHP_PSALM' + 'POWERSHELL' 'PROTOBUF' 'PYTHON_BLACK' 'PYTHON_PYLINT' 'PYTHON_FLAKE8' + 'PYTHON_ISORT' 'PYTHON_MYPY' 'R' 'RAKU' 'RUBY' 'RUST_2015' 'RUST_2018' + 'RUST_CLIPPY' 'SHELL_SHFMT' 'SNAKEMAKE_LINT' 'SNAKEMAKE_SNAKEFMT' 'STATES' + 'SQL' 'TEKTON' 'TERRAFORM' 'TERRAFORM_TERRASCAN' 'TERRAGRUNT' 'TSX' + 'TYPESCRIPT_ES' 'TYPESCRIPT_STANDARD' 'XML' 'YAML') ############################## # Linter command names array # @@ -210,6 +213,7 @@ LINTER_NAMES_ARRAY['ANSIBLE']="ansible-lint" LINTER_NAMES_ARRAY['ARM']="arm-ttk" LINTER_NAMES_ARRAY['BASH']="shellcheck" LINTER_NAMES_ARRAY['BASH_EXEC']="bash-exec" +LINTER_NAMES_ARRAY['CLANG_FORMAT']="clang-format" LINTER_NAMES_ARRAY['CLOJURE']="clj-kondo" LINTER_NAMES_ARRAY['CLOUDFORMATION']="cfn-lint" LINTER_NAMES_ARRAY['COFFEESCRIPT']="coffeelint" @@ -806,6 +810,7 @@ LINTER_COMMANDS_ARRAY['ANSIBLE']="ansible-lint -v -c ${ANSIBLE_LINTER_RULES}" LINTER_COMMANDS_ARRAY['ARM']="Import-Module ${ARM_TTK_PSD1} ; \${config} = \$(Import-PowerShellDataFile -Path ${ARM_LINTER_RULES}) ; Test-AzTemplate @config -TemplatePath" LINTER_COMMANDS_ARRAY['BASH']="shellcheck --color --external-sources" LINTER_COMMANDS_ARRAY['BASH_EXEC']="bash-exec" +LINTER_COMMANDS_ARRAY['CLANG_FORMAT']="clang-format --Werror --dry-run" LINTER_COMMANDS_ARRAY['CLOJURE']="clj-kondo --config ${CLOJURE_LINTER_RULES} --lint" LINTER_COMMANDS_ARRAY['CLOUDFORMATION']="cfn-lint --config-file ${CLOUDFORMATION_LINTER_RULES}" LINTER_COMMANDS_ARRAY['COFFEESCRIPT']="coffeelint -f ${COFFEESCRIPT_LINTER_RULES}" diff --git a/test/inspec/super-linter/controls/super_linter.rb b/test/inspec/super-linter/controls/super_linter.rb index 94852388..e4fdd0cd 100644 --- a/test/inspec/super-linter/controls/super_linter.rb +++ b/test/inspec/super-linter/controls/super_linter.rb @@ -94,6 +94,7 @@ control "super-linter-installed-commands" do { linter_name: "asl-validator"}, { linter_name: "bash-exec", expected_exit_status: 1}, # expect a return code = 1 because this linter doesn't support a "get linter version" command { linter_name: "black"}, + { linter_name: "clang-format"}, { linter_name: "cfn-lint"}, { linter_name: "checkstyle", version_command: "java -jar /usr/bin/checkstyle --version"}, { linter_name: "chktex"},