From 37ef4fb92b20356a8c2a8de44ab04a4d0adb8575 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Thu, 26 Mar 2026 14:52:23 +0100 Subject: [PATCH 1/8] CI yamllint: lint all changed files Filter out files inside the .yamllint configuration --- .github/workflows/ci_lint.yml | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci_lint.yml b/.github/workflows/ci_lint.yml index 7ff16b73dc4f..7324698ca99e 100644 --- a/.github/workflows/ci_lint.yml +++ b/.github/workflows/ci_lint.yml @@ -6,7 +6,7 @@ permissions: contents: read jobs: yamllint: - name: Yaml Lint on Changed Controls and Profiles Files + name: Yaml Lint on Changed yaml files runs-on: ubuntu-latest steps: - name: Install Git @@ -27,18 +27,6 @@ jobs: url="repos/$repo/pulls/$pr_number/files" response=$(gh api "$url" --paginate) echo "$response" | jq -r '.[].filename' > filenames.txt - cat filenames.txt - - if grep -q "controls/" filenames.txt; then - echo "CONTROLS_CHANGES=true" >> $GITHUB_ENV - else - echo "CONTROLS_CHANGES=false" >> $GITHUB_ENV - fi - if grep -q "\.profile" filenames.txt; then - echo "PROFILES_CHANGES=true" >> $GITHUB_ENV - else - echo "PROFILES_CHANGES=false" >> $GITHUB_ENV - fi env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -46,18 +34,9 @@ jobs: if: ${{ env.CONTROLS_CHANGES == 'true' || env.PROFILES_CHANGES == 'true' }} run: pip install yamllint - - name: Run yamllint in Control Files Modified by PR - if: ${{ env.CONTROLS_CHANGES == 'true' }} - run: | - for control_file in $(cat filenames.txt | grep "controls/"); do - echo "Running yamllint on $control_file..." - yamllint "$control_file" - done - - - name: Run yamllint in Profile Files Modified by PR - if: ${{ env.PROFILES_CHANGES == 'true' }} + - name: Run yamllint on files modified by the PR run: | - for profile_file in $(cat filenames.txt | grep "\.profile"); do - echo "Running yamllint on $profile_file..." - yamllint "$profile_file" + for file in $(cat filenames.txt); do + echo "Running yamllint on $file..." + yamllint -c .yamllint "$file" done From 975e2d67bd8250136ddaffa2d8df6278a969e7f6 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Fri, 27 Mar 2026 12:47:51 +0100 Subject: [PATCH 2/8] yamllint config: lint only certain file extensions also enforce line length of 99 --- .yamllint | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.yamllint b/.yamllint index 7a97bcd9229b..83b0319dc670 100644 --- a/.yamllint +++ b/.yamllint @@ -1,5 +1,10 @@ --- extends: default +locale: en_US.UTF-8 +yaml-files: + - "*.yaml" + - "*.yml" + - "*.fmf" # https://yamllint.readthedocs.io/en/stable/rules.html rules: @@ -10,4 +15,5 @@ rules: level: warning indentation: spaces: consistent - line-length: disable + line-length: + max: 99 From a4e4e59c31d6797ae27bf0b002295552033af91d Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Fri, 27 Mar 2026 14:04:07 +0100 Subject: [PATCH 3/8] yamllint config: add comments and disable truthy rule --- .yamllint | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.yamllint b/.yamllint index 83b0319dc670..0ea0118098df 100644 --- a/.yamllint +++ b/.yamllint @@ -8,12 +8,13 @@ yaml-files: # https://yamllint.readthedocs.io/en/stable/rules.html rules: - comments: disable - comments-indentation: disable - document-start: disable + truthy: disable # do not check for strict true / false boolean values + comments: disable # disable syntax checking of comments + comments-indentation: disable # disable indentation checks for comments + document-start: disable # do not require the document start marker empty-lines: - level: warning + level: warning # only warn about empty lines indentation: - spaces: consistent + spaces: consistent # pass lint if spaces are used for indentation and multiple of spaces is consistent through a file line-length: - max: 99 + max: 99 # allow lines up to 99 chars From f4ee494c34b0a1edb4051b736c1226099d937907 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Fri, 27 Mar 2026 14:04:24 +0100 Subject: [PATCH 4/8] fix lint error in the workflow file --- .github/workflows/ci_lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_lint.yml b/.github/workflows/ci_lint.yml index 7324698ca99e..000615977861 100644 --- a/.github/workflows/ci_lint.yml +++ b/.github/workflows/ci_lint.yml @@ -3,7 +3,7 @@ on: pull_request: branches: [master, 'stabilization*'] permissions: - contents: read + contents: read jobs: yamllint: name: Yaml Lint on Changed yaml files From 02bffa89ecfdc176696c9f2be2b2528155c52d90 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Fri, 27 Mar 2026 14:16:33 +0100 Subject: [PATCH 5/8] fix lint errors in the yamllint configuration it self --- .yamllint | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.yamllint b/.yamllint index 0ea0118098df..7279f41e5e5c 100644 --- a/.yamllint +++ b/.yamllint @@ -11,10 +11,11 @@ rules: truthy: disable # do not check for strict true / false boolean values comments: disable # disable syntax checking of comments comments-indentation: disable # disable indentation checks for comments - document-start: disable # do not require the document start marker + document-start: disable # do not require the document start marker empty-lines: level: warning # only warn about empty lines indentation: - spaces: consistent # pass lint if spaces are used for indentation and multiple of spaces is consistent through a file + # pass if spaces are used for indentation and number of spaces is consistent through a file + spaces: consistent line-length: max: 99 # allow lines up to 99 chars From 57094c25453a9d24214b9ad44559d10091a1d9b3 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Tue, 31 Mar 2026 11:38:56 +0200 Subject: [PATCH 6/8] cover also .profile files --- .yamllint | 1 + 1 file changed, 1 insertion(+) diff --git a/.yamllint b/.yamllint index 7279f41e5e5c..d739d0536d28 100644 --- a/.yamllint +++ b/.yamllint @@ -5,6 +5,7 @@ yaml-files: - "*.yaml" - "*.yml" - "*.fmf" + - "*.profile" # https://yamllint.readthedocs.io/en/stable/rules.html rules: From 5fa35ca555171b57367db42a1632aa6c3aa9b4e6 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Thu, 2 Apr 2026 10:28:45 +0200 Subject: [PATCH 7/8] remove forgotten conditional from workflow --- .github/workflows/ci_lint.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci_lint.yml b/.github/workflows/ci_lint.yml index 000615977861..c93cc3f0eb40 100644 --- a/.github/workflows/ci_lint.yml +++ b/.github/workflows/ci_lint.yml @@ -31,7 +31,6 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install yamllint - if: ${{ env.CONTROLS_CHANGES == 'true' || env.PROFILES_CHANGES == 'true' }} run: pip install yamllint - name: Run yamllint on files modified by the PR From 79b309db7499fc9e312d242feb077b208d354e74 Mon Sep 17 00:00:00 2001 From: Vojtech Polasek Date: Thu, 2 Apr 2026 11:28:25 +0200 Subject: [PATCH 8/8] strip Jinja constructs before running yamllint Many YAML files in this project contain Jinja2 templating ({{% %}}, {{{ }}}, {{# #}}) which causes yamllint to report false syntax errors. Add a helper script (utils/strip_jinja_for_yamllint.py) that removes Jinja constructs while preserving line numbers, and update the CI workflow to use it for files that contain Jinja. Files without Jinja are linted directly as before. Warnings are reported but do not fail the job. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/ci_lint.yml | 28 ++++++++++- utils/strip_jinja_for_yamllint.py | 78 +++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 utils/strip_jinja_for_yamllint.py diff --git a/.github/workflows/ci_lint.yml b/.github/workflows/ci_lint.yml index c93cc3f0eb40..696887ce7572 100644 --- a/.github/workflows/ci_lint.yml +++ b/.github/workflows/ci_lint.yml @@ -35,7 +35,33 @@ jobs: - name: Run yamllint on files modified by the PR run: | + exit_code=0 for file in $(cat filenames.txt); do + if [[ ! -f "$file" ]]; then + continue + fi echo "Running yamllint on $file..." - yamllint -c .yamllint "$file" + if grep -qP '\{\{[%{#]' "$file"; then + # File contains Jinja2 constructs — strip them before linting. + # yamllint -s exits: 0 = clean, 1 = errors, 2 = warnings only. + output=$(python3 utils/strip_jinja_for_yamllint.py "$file" \ + | yamllint -s -c .yamllint - 2>&1) + rc=$? + # Show all output (warnings and errors), replacing "stdin" + # with the actual filename since yamllint reads from a pipe. + if [ -n "$output" ]; then + echo "$output" | sed "s|^stdin|$file|" + fi + # Fail only on errors (exit code 1), not warnings (exit code 2). + if [ "$rc" -eq 1 ]; then + exit_code=1 + fi + else + yamllint -s -c .yamllint "$file" + rc=$? + if [ "$rc" -eq 1 ]; then + exit_code=1 + fi + fi done + exit $exit_code diff --git a/utils/strip_jinja_for_yamllint.py b/utils/strip_jinja_for_yamllint.py new file mode 100644 index 000000000000..b0782bb23b76 --- /dev/null +++ b/utils/strip_jinja_for_yamllint.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""Strip Jinja2 constructs from YAML files to make them yamllint-safe. + +This project uses Jinja2 templating ({{% %}}, {{{ }}}, {{# #}}) inside YAML +files. yamllint cannot parse these constructs, so this script removes them +while preserving line numbers (replaced regions become blank lines) so that +yamllint error messages still point to the correct source lines. + +Usage: + python3 utils/strip_jinja_for_yamllint.py FILE + +The cleaned content is written to stdout. +""" + +import re +import sys + + +def _replace_with_blanks(match): + """Replace a match with the same number of newlines to preserve line numbers.""" + return "\n" * match.group(0).count("\n") + + +def strip_jinja(content): + # 1. Remove whole-line Jinja block tags: {{% ... %}} on their own line(s). + # Match the entire line (including leading whitespace) to avoid leaving + # trailing spaces behind. + content = re.sub( + r"^[ \t]*\{\{%.*?%\}\}[ \t]*$", + _replace_with_blanks, + content, + flags=re.MULTILINE | re.DOTALL, + ) + # Remove any remaining inline block tags (rare). + content = re.sub(r"\{\{%.*?%\}\}", _replace_with_blanks, content, flags=re.DOTALL) + + # 2. Remove whole-line Jinja comments: {{# ... #}} + content = re.sub( + r"^[ \t]*\{\{#.*?#\}\}[ \t]*$", + _replace_with_blanks, + content, + flags=re.MULTILINE | re.DOTALL, + ) + # Remove any remaining inline comments. + content = re.sub(r"\{\{#.*?#\}\}", "", content, flags=re.DOTALL) + + # 3a. Standalone Jinja expressions occupying entire lines — these typically + # expand to top-level YAML keys (e.g. ocil/ocil_clause macros) or + # Ansible tasks, so replacing them with a placeholder string would + # produce invalid YAML. Replace with a YAML-safe comment placeholder + # to avoid trailing whitespace on otherwise blank lines. + content = re.sub( + r"^([ \t]*)\{\{\{.*?\}\}\}[ \t]*$", + lambda m: m.group(1) + "# jinja" + "\n" * (m.group(0).count("\n") - 1) + if m.group(0).count("\n") > 0 + else m.group(1) + "# jinja", + content, + flags=re.MULTILINE | re.DOTALL, + ) + + # 3b. Inline Jinja expressions embedded inside a YAML value — replace + # with a short placeholder so the surrounding YAML stays valid. + content = re.sub(r"\{\{\{.*?\}\}\}", "JINJA_EXPRESSION", content) + + return content + + +def main(): + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} FILE", file=sys.stderr) + sys.exit(2) + + with open(sys.argv[1]) as f: + sys.stdout.write(strip_jinja(f.read())) + + +if __name__ == "__main__": + main()