diff --git a/.ecrc b/.ecrc index dc16bb7a..8331478d 100644 --- a/.ecrc +++ b/.ecrc @@ -5,6 +5,7 @@ "__pycache__[/\\\\]", "node_modules[/\\\\]", "^other[/\\\\]clang-format-configuration[/\\\\]testdata[/\\\\]", + "^other[/\\\\]clang-format-configuration[/\\\\]\\.clang-format", "^LICENSE\\.txt$", "^poetry\\.lock$" ] diff --git a/.github/workflows/check-clang-format.yml b/.github/workflows/check-clang-format.yml index c4f9230c..d1c0b7cb 100644 --- a/.github/workflows/check-clang-format.yml +++ b/.github/workflows/check-clang-format.yml @@ -58,6 +58,65 @@ jobs: - name: Validate ClangFormat configuration files run: task --silent clang-format:validate + check-config: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Set environment variables + run: | + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable + if [[ "${{ github.event.inputs.clang-format-version }}" == "" ]]; then + echo "CLANG_FORMAT_VERSION=$(task clang-format:get-version)" >> "$GITHUB_ENV" + else + echo "CLANG_FORMAT_VERSION=${{ github.event.inputs.clang-format-version }}" >> "$GITHUB_ENV" + fi + echo "CLANG_FORMAT_INSTALL_PATH=${{ runner.temp }}/clang-format" >> "$GITHUB_ENV" + echo "WORKING_FOLDER=${{ runner.temp }}" >> "$GITHUB_ENV" + + - name: Download ClangFormat + id: download + uses: MrOctopus/download-asset-action@1.0 + with: + repository: arduino/clang-static-binaries + tag: ${{ env.CLANG_FORMAT_VERSION }} + asset: clang-format_${{ env.CLANG_FORMAT_VERSION }}_Linux_64bit.tar.bz2 + target: ${{ env.CLANG_FORMAT_INSTALL_PATH }} + + - name: Install ClangFormat + run: | + cd "${{ env.CLANG_FORMAT_INSTALL_PATH }}" + tar --extract --file="${{ steps.download.outputs.name }}" + # Add installation to PATH: + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path + echo "${{ env.CLANG_FORMAT_INSTALL_PATH }}/clang_Linux_64bit" >> "$GITHUB_PATH" + + - name: Check ClangFormat configuration file + id: check + run: | + task \ + --silent \ + clang-format:check-config \ + CLANG_FORMAT_VERSION="${{ env.CLANG_FORMAT_VERSION }}" + + - name: Save effective configuration file to a workflow artifact + if: > + always() && + steps.check.outcome == 'failure' + uses: actions/upload-artifact@v3 + with: + path: ${{ env.WORKING_FOLDER }}/expected/.clang-format + if-no-files-found: error + name: config-output + check-output: runs-on: ubuntu-latest diff --git a/.prettierignore b/.prettierignore index da14dbf9..99d17548 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,3 +3,4 @@ __pycache__/ node_modules/ /other/clang-format-configuration/testdata/golden/samples/ /other/clang-format-configuration/testdata/input/samples/ +/other/clang-format-configuration/.clang-format diff --git a/.yamllint.yml b/.yamllint.yml index 67630dcc..1a36cbaf 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -72,5 +72,6 @@ yaml-files: ignore: | /.git/ + /other/clang-format-configuration/.clang-format __pycache__/ node_modules/ diff --git a/Taskfile.yml b/Taskfile.yml index adf6fa9d..1879c2f6 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -17,6 +17,7 @@ tasks: desc: Check for problems with the project deps: - task: ci:validate + - task: clang-format:check-config - task: clang-format:check-output - task: clang-format:check-testdata - task: clang-format:validate @@ -111,6 +112,32 @@ tasks: -s "{{.WORKFLOW_SCHEMA_PATH}}" \ -d "{{.TEMPLATE_WORKFLOWS_DATA_PATH}}" + clang-format:check-config: + desc: Check that ClangFormat configuration file matches effective tool configuration + vars: + WORKING_FOLDER: + sh: | + if [[ "{{.WORKING_FOLDER}}" == "" ]]; then + # Generate a path + task utility:mktemp-folder TEMPLATE="clang-format-check-config-XXXXXXXXXX" + else + # A path was specified via the command line + echo "{{.WORKING_FOLDER}}" + fi + ACTUAL_CONFIGURATION_PATH: "{{.WORKING_FOLDER}}/actual/.clang-format" + EXPECTED_CONFIGURATION_PATH: "{{.WORKING_FOLDER}}/expected/.clang-format" + cmds: + - | + mkdir "{{.WORKING_FOLDER}}/actual" + mkdir "{{.WORKING_FOLDER}}/expected" + cp "{{.CLANG_FORMAT_CONFIGURATION_PATH}}" "{{.WORKING_FOLDER}}/actual/" + - task: clang-format:dump-config + vars: + TARGET_PATH: "{{.WORKING_FOLDER}}/expected/.clang-format" + - | + cd "{{.WORKING_FOLDER}}" + diff --color=always --unified "actual/.clang-format" "expected/.clang-format" + # Check if ClangFormat is installed and the expected version clang-format:check-installed: vars: @@ -198,6 +225,23 @@ tasks: "{{.CLANG_FORMAT_CONFIGURATION_PATH}}" \ "{{.OUTPUT_PATH}}" + # Write the effective ClangFormat configuration to the path specified by the TARGET_PATH variable + clang-format:dump-config: + deps: + - task: clang-format:check-installed + cmds: + - | + # Add source comment + echo \ + "# Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration" > \ + "{{.TARGET_PATH}}" + + # Dump the effective configuration to the target file + clang-format \ + --dump-config \ + --style=file:"{{.CLANG_FORMAT_CONFIGURATION_PATH}}" >> \ + "{{.TARGET_PATH}}" + # Use ClangFormat to format the files under the path specified by TARGET_FOLDER recursively clang-format:format: cmds: @@ -226,6 +270,13 @@ tasks: cmds: - echo "{{.DEFAULT_CLANG_FORMAT_VERSION}}" + clang-format:update-config: + desc: Update ClangFormat configuration file to match effective tool configuration + cmds: + - task: clang-format:dump-config + vars: + TARGET_PATH: "{{.CLANG_FORMAT_CONFIGURATION_PATH}}" + clang-format:update-golden: desc: Update golden master test data for current configuration deps: @@ -276,7 +327,6 @@ tasks: "{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/general/.editorconfig" \ "{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-python/.flake8" \ "{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-markdown/.markdownlint.yml" \ - "{{.WORKFLOW_TEMPLATE_ASSETS_PATH}}/check-yaml/.yamllint.yml" \ "{{.REPOSITORY_ROOT_PATH}}" dependabot:validate: diff --git a/other/clang-format-configuration/.clang-format b/other/clang-format-configuration/.clang-format index 05128236..efbc0c0b 100644 --- a/other/clang-format-configuration/.clang-format +++ b/other/clang-format-configuration/.clang-format @@ -1,25 +1,24 @@ # Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration --- -Language: Cpp -BasedOnStyle: LLVM +Language: Cpp AccessModifierOffset: -2 AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false AlignConsecutiveAssignments: false AlignConsecutiveBitFields: false AlignConsecutiveDeclarations: false -AlignConsecutiveMacros: false AlignEscapedNewlines: DontAlign -AlignOperands: Align +AlignOperands: Align AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: true -AllowShortEnumsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: Always AllowShortLambdasOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Always AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None @@ -28,33 +27,35 @@ AlwaysBreakTemplateDeclarations: No BinPackArguments: true BinPackParameters: true BraceWrapping: - AfterCaseLabel: false - AfterClass: false + AfterCaseLabel: false + AfterClass: false AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - #AfterObjCDeclaration: - AfterStruct: false - AfterUnion: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false AfterExternBlock: false - BeforeCatch: false - BeforeElse: false + BeforeCatch: false + BeforeElse: false BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false -#BreakAfterJavaFieldAnnotations: + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon -BreakInheritanceList: BeforeColon +BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false -ColumnLimit: 0 -CommentPragmas: "" +ColumnLimit: 0 +CommentPragmas: '' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 2 @@ -62,36 +63,46 @@ ContinuationIndentWidth: 2 Cpp11BracedListStyle: false DeriveLineEnding: true DerivePointerAlignment: true -DisableFormat: false -#ExperimentalAutoDetectBinPacking: +DisableFormat: false +ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false -ForEachMacros: [] -IncludeBlocks: Preserve -IncludeCategories: [] -IncludeIsMainRegex: "" -IncludeIsMainSourceRegex: "" -IndentCaseBlocks: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '' +IncludeIsMainSourceRegex: '' IndentCaseLabels: true -IndentExternBlock: Indent +IndentCaseBlocks: true IndentGotoLabels: false IndentPPDirectives: None -IndentWidth: 2 +IndentExternBlock: Indent +IndentWidth: 2 IndentWrappedFunctionNames: false InsertTrailingCommas: None -#JavaImportGroups: -#JavaScriptQuotes: -#JavaScriptWrapImports: +JavaScriptQuotes: Leave +JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: "" -MacroBlockEnd: "" +MacroBlockBegin: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 100000 NamespaceIndentation: None -NamespaceMacros: [] -#ObjCBinPackProtocolList: -#ObjCBlockIndentWidth: -#ObjCBreakBeforeNestedBlockParam: -#ObjCSpaceAfterProperty: -#ObjCSpaceBeforeProtocolList: +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 1 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 1 @@ -101,9 +112,8 @@ PenaltyBreakTemplateDeclaration: 1 PenaltyExcessCharacter: 1 PenaltyReturnTypeOnItsOwnLine: 1 PointerAlignment: Right -RawStringFormats: [] -ReflowComments: false -SortIncludes: false +ReflowComments: false +SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false @@ -114,20 +124,26 @@ SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInCStyleCastParentheses: false +SpacesInAngles: false SpacesInConditionalStatement: false SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false -Standard: Auto -StatementMacros: [] -TabWidth: 2 -TypenameMacros: [] -UseCRLF: false -UseTab: Never -WhitespaceSensitiveMacros: [] +SpaceBeforeSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 2 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE +... + diff --git a/other/clang-format-configuration/README.md b/other/clang-format-configuration/README.md index da8caf25..fd27bef0 100644 --- a/other/clang-format-configuration/README.md +++ b/other/clang-format-configuration/README.md @@ -79,6 +79,26 @@ As an alternative to running the update command locally, you can download the fi Save the contents of the downloaded ZIP file to [the `testdata/golden/` folder](testdata/golden/). +### Updating the configuration file + +In order to detect added keys, removed keys, or changes to the type of existing keys resulting from a **ClangFormat** version update, the configuration file is used as a "golden master" which the output of `clang-format --dump-config` is compared against. + +At the conclusion of the investigation of any output, the configuration file may need to be updated to match the new output: + +#### Via local operation + +Run the following command + +```text +task clang-format:update-config +``` + +#### Via GitHub Actions + +As an alternative to running the update command locally, you can download the files from a workflow artifact named "**config-output**" which is available in the "**Summary**" page of each workflow run where the `check-config` job of the "**Check ClangFormat Configuration**" workflow failed due to the current configuration file not matching the `--dump-config` output. + +Replace [`.clang-format`](.clang-format) with the one from the downloaded ZIP file. + ## Configuration notes Notes about the **ClangFormat** configuration are recorded [here](notes.md).