cfengine 0.14.0__tar.gz → 0.15.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. cfengine-0.15.0/.github/workflows/lint-policy-in-other-repos.yml +47 -0
  2. {cfengine-0.14.0 → cfengine-0.15.0}/PKG-INFO +1 -1
  3. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/PKG-INFO +1 -1
  4. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/SOURCES.txt +55 -54
  5. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/lint.py +51 -9
  6. cfengine-0.15.0/src/cfengine_cli/lint_csv.py +52 -0
  7. cfengine-0.15.0/tests/lint/002_deprecations.expected.txt +17 -0
  8. cfengine-0.14.0/tests/lint/002_ifvarclass.x.cf → cfengine-0.15.0/tests/lint/002_deprecations.x.cf +4 -0
  9. cfengine-0.15.0/tests/lint/003_name_lowercase.cf +16 -0
  10. cfengine-0.15.0/tests/lint/003_name_lowercase.expected.txt +16 -0
  11. cfengine-0.15.0/tests/lint/003_name_lowercase.x.cf +16 -0
  12. cfengine-0.15.0/tests/lint/004_block_type.cf +11 -0
  13. cfengine-0.15.0/tests/lint/004_block_type.expected.txt +11 -0
  14. cfengine-0.15.0/tests/lint/004_block_type.x.cf +11 -0
  15. cfengine-0.15.0/tests/lint/005_syntax_error.expected.txt +7 -0
  16. cfengine-0.15.0/tests/lint/006_empty_file.expected.txt +3 -0
  17. cfengine-0.14.0/tests/lint/008_namespace.expected.txt → cfengine-0.15.0/tests/lint/007_namespace.expected.txt +2 -2
  18. cfengine-0.14.0/tests/lint/009_bundle_shadows_function.expected.txt → cfengine-0.15.0/tests/lint/008_bundle_shadows_function.expected.txt +2 -2
  19. cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.expected.txt → cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.expected.txt +3 -3
  20. cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.expected.txt → cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.expected.txt +3 -3
  21. cfengine-0.14.0/tests/lint/012_invalid_attributes.expected.txt → cfengine-0.15.0/tests/lint/011_invalid_attributes.expected.txt +3 -3
  22. cfengine-0.14.0/tests/lint/013_function_call_arg_count.expected.txt → cfengine-0.15.0/tests/lint/012_function_call_arg_count.expected.txt +3 -3
  23. cfengine-0.14.0/tests/lint/014_num_args_body.expected.txt → cfengine-0.15.0/tests/lint/013_num_args_body.expected.txt +7 -7
  24. cfengine-0.14.0/tests/lint/014_num_args_bundle.expected.txt → cfengine-0.15.0/tests/lint/013_num_args_bundle.expected.txt +7 -7
  25. cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.expected.txt → cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.expected.txt +3 -3
  26. cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.expected.txt +14 -0
  27. cfengine-0.14.0/tests/lint/017_half_promises.expected.txt → cfengine-0.15.0/tests/lint/016_half_promises.expected.txt +4 -4
  28. cfengine-0.14.0/tests/lint/018_implies_body.expected.txt → cfengine-0.15.0/tests/lint/017_implies_body.expected.txt +9 -9
  29. cfengine-0.14.0/tests/lint/019_nested_calls.expected.txt → cfengine-0.15.0/tests/lint/018_nested_calls.expected.txt +5 -5
  30. cfengine-0.15.0/tests/shell/005-lint.sh +46 -0
  31. cfengine-0.15.0/tests/unit/test_lint_csv.py +73 -0
  32. cfengine-0.14.0/tests/lint/002_ifvarclass.expected.txt +0 -7
  33. cfengine-0.14.0/tests/lint/003_deprecated_promise_type.cf +0 -5
  34. cfengine-0.14.0/tests/lint/003_deprecated_promise_type.expected.txt +0 -7
  35. cfengine-0.14.0/tests/lint/003_deprecated_promise_type.x.cf +0 -5
  36. cfengine-0.14.0/tests/lint/004_bundle_name_lowercase.cf +0 -5
  37. cfengine-0.14.0/tests/lint/004_bundle_name_lowercase.expected.txt +0 -6
  38. cfengine-0.14.0/tests/lint/004_bundle_name_lowercase.x.cf +0 -5
  39. cfengine-0.14.0/tests/lint/005_bundle_type.cf +0 -5
  40. cfengine-0.14.0/tests/lint/005_bundle_type.expected.txt +0 -6
  41. cfengine-0.14.0/tests/lint/005_bundle_type.x.cf +0 -5
  42. cfengine-0.14.0/tests/lint/006_syntax_error.expected.txt +0 -7
  43. cfengine-0.14.0/tests/lint/007_empty_file.expected.txt +0 -3
  44. cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.expected.txt +0 -14
  45. {cfengine-0.14.0 → cfengine-0.15.0}/.github/dependabot.yml +0 -0
  46. {cfengine-0.14.0 → cfengine-0.15.0}/.github/workflows/make-check.yml +0 -0
  47. {cfengine-0.14.0 → cfengine-0.15.0}/.github/workflows/pypi-publish.yml +0 -0
  48. {cfengine-0.14.0 → cfengine-0.15.0}/.github/workflows/update-syntax-description.yml +0 -0
  49. {cfengine-0.14.0 → cfengine-0.15.0}/.gitignore +0 -0
  50. {cfengine-0.14.0 → cfengine-0.15.0}/.python-version +0 -0
  51. {cfengine-0.14.0 → cfengine-0.15.0}/CLAUDE.md +0 -0
  52. {cfengine-0.14.0 → cfengine-0.15.0}/HACKING.md +0 -0
  53. {cfengine-0.14.0 → cfengine-0.15.0}/LICENSE +0 -0
  54. {cfengine-0.14.0 → cfengine-0.15.0}/Makefile +0 -0
  55. {cfengine-0.14.0 → cfengine-0.15.0}/README.md +0 -0
  56. {cfengine-0.14.0 → cfengine-0.15.0}/ci/01-install.sh +0 -0
  57. {cfengine-0.14.0 → cfengine-0.15.0}/ci/02-safe-tests.sh +0 -0
  58. {cfengine-0.14.0 → cfengine-0.15.0}/ci/03-unsafe-tests.sh +0 -0
  59. {cfengine-0.14.0 → cfengine-0.15.0}/pyproject.toml +0 -0
  60. {cfengine-0.14.0 → cfengine-0.15.0}/setup.cfg +0 -0
  61. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
  62. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/entry_points.txt +0 -0
  63. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/requires.txt +0 -0
  64. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine.egg-info/top_level.txt +0 -0
  65. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/__init__.py +0 -0
  66. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/__main__.py +0 -0
  67. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/commands.py +0 -0
  68. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/deptool-README.md +0 -0
  69. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/deptool.py +0 -0
  70. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/dev.py +0 -0
  71. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/docs.py +0 -0
  72. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/format.py +0 -0
  73. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/main.py +0 -0
  74. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
  75. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/analyze.py +0 -0
  76. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
  77. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/download.py +0 -0
  78. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
  79. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
  80. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
  81. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
  82. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/paths.py +0 -0
  83. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/profile.py +0 -0
  84. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/shell.py +0 -0
  85. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/syntax-description.json +0 -0
  86. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/syntax_tree.py +0 -0
  87. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/utils.py +0 -0
  88. {cfengine-0.14.0 → cfengine-0.15.0}/src/cfengine_cli/version.py +0 -0
  89. {cfengine-0.14.0 → cfengine-0.15.0}/tests/README.md +0 -0
  90. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/001_hello_world.expected.cf +0 -0
  91. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/001_hello_world.input.cf +0 -0
  92. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/002_basics.expected.cf +0 -0
  93. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/002_basics.input.cf +0 -0
  94. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/003_wrapping.expected.cf +0 -0
  95. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/003_wrapping.input.cf +0 -0
  96. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/004_comments.expected.cf +0 -0
  97. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/004_comments.input.cf +0 -0
  98. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/005_bundle_comments.expected.cf +0 -0
  99. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/005_bundle_comments.input.cf +0 -0
  100. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/006_remove_empty_comments.expected.cf +0 -0
  101. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/006_remove_empty_comments.input.cf +0 -0
  102. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/007_class_guarded_empty_lines.expected.cf +0 -0
  103. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
  104. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/008_long_string.expected.cf +0 -0
  105. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/008_long_string.input.cf +0 -0
  106. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/009_single_line.expected.cf +0 -0
  107. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/009_single_line.input.cf +0 -0
  108. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/010_stakeholder.expected.cf +0 -0
  109. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/010_stakeholder.input.cf +0 -0
  110. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/011_macros.expected.cf +0 -0
  111. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/011_macros.input.cf +0 -0
  112. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/011_promises.expected.cf +0 -0
  113. {cfengine-0.14.0 → cfengine-0.15.0}/tests/format/011_promises.input.cf +0 -0
  114. {cfengine-0.14.0 → cfengine-0.15.0}/tests/lint/001_hello_world.cf +0 -0
  115. /cfengine-0.14.0/tests/lint/006_syntax_error.cf → /cfengine-0.15.0/tests/lint/005_syntax_error.cf +0 -0
  116. /cfengine-0.14.0/tests/lint/006_syntax_error.x.cf → /cfengine-0.15.0/tests/lint/005_syntax_error.x.cf +0 -0
  117. /cfengine-0.14.0/tests/lint/007_empty_file.x.cf → /cfengine-0.15.0/tests/lint/006_empty_file.x.cf +0 -0
  118. /cfengine-0.14.0/tests/lint/008_namespace.cf → /cfengine-0.15.0/tests/lint/007_namespace.cf +0 -0
  119. /cfengine-0.14.0/tests/lint/008_namespace.x.cf → /cfengine-0.15.0/tests/lint/007_namespace.x.cf +0 -0
  120. /cfengine-0.14.0/tests/lint/009_bundle_shadows_function.cf → /cfengine-0.15.0/tests/lint/008_bundle_shadows_function.cf +0 -0
  121. /cfengine-0.14.0/tests/lint/009_bundle_shadows_function.x.cf → /cfengine-0.15.0/tests/lint/008_bundle_shadows_function.x.cf +0 -0
  122. /cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.cf → /cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.cf +0 -0
  123. /cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.x.cf → /cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.x.cf +0 -0
  124. /cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.cf → /cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.cf +0 -0
  125. /cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.x.cf → /cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.x.cf +0 -0
  126. /cfengine-0.14.0/tests/lint/012_invalid_attributes.x.cf → /cfengine-0.15.0/tests/lint/011_invalid_attributes.x.cf +0 -0
  127. /cfengine-0.14.0/tests/lint/013_function_call_arg_count.cf → /cfengine-0.15.0/tests/lint/012_function_call_arg_count.cf +0 -0
  128. /cfengine-0.14.0/tests/lint/013_function_call_arg_count.x.cf → /cfengine-0.15.0/tests/lint/012_function_call_arg_count.x.cf +0 -0
  129. /cfengine-0.14.0/tests/lint/014_num_args_body.x.cf → /cfengine-0.15.0/tests/lint/013_num_args_body.x.cf +0 -0
  130. /cfengine-0.14.0/tests/lint/014_num_args_bundle.x.cf → /cfengine-0.15.0/tests/lint/013_num_args_bundle.x.cf +0 -0
  131. /cfengine-0.14.0/tests/lint/014_num_args_bundle_body.cf → /cfengine-0.15.0/tests/lint/013_num_args_bundle_body.cf +0 -0
  132. /cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.cf → /cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.cf +0 -0
  133. /cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.x.cf → /cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.x.cf +0 -0
  134. /cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.cf → /cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.cf +0 -0
  135. /cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.x.cf → /cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.x.cf +0 -0
  136. /cfengine-0.14.0/tests/lint/017_half_promises.cf → /cfengine-0.15.0/tests/lint/016_half_promises.cf +0 -0
  137. /cfengine-0.14.0/tests/lint/017_half_promises.x.cf → /cfengine-0.15.0/tests/lint/016_half_promises.x.cf +0 -0
  138. /cfengine-0.14.0/tests/lint/018_implies_body.cf → /cfengine-0.15.0/tests/lint/017_implies_body.cf +0 -0
  139. /cfengine-0.14.0/tests/lint/018_implies_body.x.cf → /cfengine-0.15.0/tests/lint/017_implies_body.x.cf +0 -0
  140. /cfengine-0.14.0/tests/lint/019_nested_calls.cf → /cfengine-0.15.0/tests/lint/018_nested_calls.cf +0 -0
  141. /cfengine-0.14.0/tests/lint/019_nested_calls.x.cf → /cfengine-0.15.0/tests/lint/018_nested_calls.x.cf +0 -0
  142. /cfengine-0.14.0/tests/lint/020_bundle_name_expansion.cf → /cfengine-0.15.0/tests/lint/019_bundle_name_expansion.cf +0 -0
  143. {cfengine-0.14.0 → cfengine-0.15.0}/tests/run-format-tests.sh +0 -0
  144. {cfengine-0.14.0 → cfengine-0.15.0}/tests/run-lint-tests.sh +0 -0
  145. {cfengine-0.14.0 → cfengine-0.15.0}/tests/run-shell-tests.sh +0 -0
  146. {cfengine-0.14.0 → cfengine-0.15.0}/tests/shell/001-help.sh +0 -0
  147. {cfengine-0.14.0 → cfengine-0.15.0}/tests/shell/002-version.sh +0 -0
  148. {cfengine-0.14.0 → cfengine-0.15.0}/tests/shell/003-format.sh +0 -0
  149. {cfengine-0.14.0 → cfengine-0.15.0}/tests/shell/004-format-check.sh +0 -0
  150. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/__init__.py +0 -0
  151. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/test_deps.py +0 -0
  152. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/test_format.py +0 -0
  153. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/test_paths.py +0 -0
  154. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/test_utils.py +0 -0
  155. {cfengine-0.14.0 → cfengine-0.15.0}/tests/unit/test_version.py +0 -0
  156. {cfengine-0.14.0 → cfengine-0.15.0}/uv.lock +0 -0
@@ -0,0 +1,47 @@
1
+ # This workflow checks that linting works on real policy in other repos
2
+ # and ensures we fix errors in policy before merging new linting rules
3
+ # to CFEngine CLI
4
+
5
+ name: Lint policy in other repos
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ pull_request:
10
+ branches: [main]
11
+ workflow_dispatch:
12
+ permissions:
13
+ contents: read
14
+ jobs:
15
+ lint:
16
+ runs-on: ubuntu-24.04
17
+ steps:
18
+ - name: Checkout cfengine-cli
19
+ uses: actions/checkout@v4
20
+ with:
21
+ path: cfengine-cli
22
+ - name: Checkout masterfiles
23
+ uses: actions/checkout@v4
24
+ with:
25
+ repository: cfengine/masterfiles
26
+ path: masterfiles
27
+ - name: Checkout modules
28
+ uses: actions/checkout@v4
29
+ with:
30
+ repository: cfengine/modules
31
+ path: modules
32
+ - name: Set up Python
33
+ uses: actions/setup-python@v5
34
+ with:
35
+ python-version: "3.13"
36
+ - name: Install dependencies
37
+ working-directory: cfengine-cli
38
+ run: |
39
+ python -m pip install --upgrade pip
40
+ python -m pip install uv
41
+ make install
42
+ - name: Run cfengine lint
43
+ working-directory: cfengine-cli
44
+ run: |
45
+ uv run cfengine lint --strict no ../masterfiles
46
+ uv run cfengine lint --strict no ../modules
47
+ # TODO: Add documentation and core when ready
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.14.0
3
+ Version: 0.15.0
4
4
  Summary: Human-oriented CLI for interacting with CFEngine tools
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.14.0
3
+ Version: 0.15.0
4
4
  Summary: Human-oriented CLI for interacting with CFEngine tools
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -8,6 +8,7 @@ README.md
8
8
  pyproject.toml
9
9
  uv.lock
10
10
  .github/dependabot.yml
11
+ .github/workflows/lint-policy-in-other-repos.yml
11
12
  .github/workflows/make-check.yml
12
13
  .github/workflows/pypi-publish.yml
13
14
  .github/workflows/update-syntax-description.yml
@@ -29,6 +30,7 @@ src/cfengine_cli/dev.py
29
30
  src/cfengine_cli/docs.py
30
31
  src/cfengine_cli/format.py
31
32
  src/cfengine_cli/lint.py
33
+ src/cfengine_cli/lint_csv.py
32
34
  src/cfengine_cli/main.py
33
35
  src/cfengine_cli/paths.py
34
36
  src/cfengine_cli/profile.py
@@ -74,67 +76,66 @@ tests/format/011_macros.input.cf
74
76
  tests/format/011_promises.expected.cf
75
77
  tests/format/011_promises.input.cf
76
78
  tests/lint/001_hello_world.cf
77
- tests/lint/002_ifvarclass.expected.txt
78
- tests/lint/002_ifvarclass.x.cf
79
- tests/lint/003_deprecated_promise_type.cf
80
- tests/lint/003_deprecated_promise_type.expected.txt
81
- tests/lint/003_deprecated_promise_type.x.cf
82
- tests/lint/004_bundle_name_lowercase.cf
83
- tests/lint/004_bundle_name_lowercase.expected.txt
84
- tests/lint/004_bundle_name_lowercase.x.cf
85
- tests/lint/005_bundle_type.cf
86
- tests/lint/005_bundle_type.expected.txt
87
- tests/lint/005_bundle_type.x.cf
88
- tests/lint/006_syntax_error.cf
89
- tests/lint/006_syntax_error.expected.txt
90
- tests/lint/006_syntax_error.x.cf
91
- tests/lint/007_empty_file.expected.txt
92
- tests/lint/007_empty_file.x.cf
93
- tests/lint/008_namespace.cf
94
- tests/lint/008_namespace.expected.txt
95
- tests/lint/008_namespace.x.cf
96
- tests/lint/009_bundle_shadows_function.cf
97
- tests/lint/009_bundle_shadows_function.expected.txt
98
- tests/lint/009_bundle_shadows_function.x.cf
99
- tests/lint/010_unknown_function_inside_vars.cf
100
- tests/lint/010_unknown_function_inside_vars.expected.txt
101
- tests/lint/010_unknown_function_inside_vars.x.cf
102
- tests/lint/011_mutually_exclusive_types_vars.cf
103
- tests/lint/011_mutually_exclusive_types_vars.expected.txt
104
- tests/lint/011_mutually_exclusive_types_vars.x.cf
105
- tests/lint/012_invalid_attributes.expected.txt
106
- tests/lint/012_invalid_attributes.x.cf
107
- tests/lint/013_function_call_arg_count.cf
108
- tests/lint/013_function_call_arg_count.expected.txt
109
- tests/lint/013_function_call_arg_count.x.cf
110
- tests/lint/014_num_args_body.expected.txt
111
- tests/lint/014_num_args_body.x.cf
112
- tests/lint/014_num_args_bundle.expected.txt
113
- tests/lint/014_num_args_bundle.x.cf
114
- tests/lint/014_num_args_bundle_body.cf
115
- tests/lint/015_variadic_func_arg_count.cf
116
- tests/lint/015_variadic_func_arg_count.expected.txt
117
- tests/lint/015_variadic_func_arg_count.x.cf
118
- tests/lint/016_macro_multi_def_bundle.cf
119
- tests/lint/016_macro_multi_def_bundle.expected.txt
120
- tests/lint/016_macro_multi_def_bundle.x.cf
121
- tests/lint/017_half_promises.cf
122
- tests/lint/017_half_promises.expected.txt
123
- tests/lint/017_half_promises.x.cf
124
- tests/lint/018_implies_body.cf
125
- tests/lint/018_implies_body.expected.txt
126
- tests/lint/018_implies_body.x.cf
127
- tests/lint/019_nested_calls.cf
128
- tests/lint/019_nested_calls.expected.txt
129
- tests/lint/019_nested_calls.x.cf
130
- tests/lint/020_bundle_name_expansion.cf
79
+ tests/lint/002_deprecations.expected.txt
80
+ tests/lint/002_deprecations.x.cf
81
+ tests/lint/003_name_lowercase.cf
82
+ tests/lint/003_name_lowercase.expected.txt
83
+ tests/lint/003_name_lowercase.x.cf
84
+ tests/lint/004_block_type.cf
85
+ tests/lint/004_block_type.expected.txt
86
+ tests/lint/004_block_type.x.cf
87
+ tests/lint/005_syntax_error.cf
88
+ tests/lint/005_syntax_error.expected.txt
89
+ tests/lint/005_syntax_error.x.cf
90
+ tests/lint/006_empty_file.expected.txt
91
+ tests/lint/006_empty_file.x.cf
92
+ tests/lint/007_namespace.cf
93
+ tests/lint/007_namespace.expected.txt
94
+ tests/lint/007_namespace.x.cf
95
+ tests/lint/008_bundle_shadows_function.cf
96
+ tests/lint/008_bundle_shadows_function.expected.txt
97
+ tests/lint/008_bundle_shadows_function.x.cf
98
+ tests/lint/009_unknown_function_inside_vars.cf
99
+ tests/lint/009_unknown_function_inside_vars.expected.txt
100
+ tests/lint/009_unknown_function_inside_vars.x.cf
101
+ tests/lint/010_mutually_exclusive_types_vars.cf
102
+ tests/lint/010_mutually_exclusive_types_vars.expected.txt
103
+ tests/lint/010_mutually_exclusive_types_vars.x.cf
104
+ tests/lint/011_invalid_attributes.expected.txt
105
+ tests/lint/011_invalid_attributes.x.cf
106
+ tests/lint/012_function_call_arg_count.cf
107
+ tests/lint/012_function_call_arg_count.expected.txt
108
+ tests/lint/012_function_call_arg_count.x.cf
109
+ tests/lint/013_num_args_body.expected.txt
110
+ tests/lint/013_num_args_body.x.cf
111
+ tests/lint/013_num_args_bundle.expected.txt
112
+ tests/lint/013_num_args_bundle.x.cf
113
+ tests/lint/013_num_args_bundle_body.cf
114
+ tests/lint/014_variadic_func_arg_count.cf
115
+ tests/lint/014_variadic_func_arg_count.expected.txt
116
+ tests/lint/014_variadic_func_arg_count.x.cf
117
+ tests/lint/015_macro_multi_def_bundle.cf
118
+ tests/lint/015_macro_multi_def_bundle.expected.txt
119
+ tests/lint/015_macro_multi_def_bundle.x.cf
120
+ tests/lint/016_half_promises.cf
121
+ tests/lint/016_half_promises.expected.txt
122
+ tests/lint/016_half_promises.x.cf
123
+ tests/lint/017_implies_body.cf
124
+ tests/lint/017_implies_body.expected.txt
125
+ tests/lint/017_implies_body.x.cf
126
+ tests/lint/018_nested_calls.cf
127
+ tests/lint/018_nested_calls.expected.txt
128
+ tests/lint/018_nested_calls.x.cf
129
+ tests/lint/019_bundle_name_expansion.cf
131
130
  tests/shell/001-help.sh
132
131
  tests/shell/002-version.sh
133
132
  tests/shell/003-format.sh
134
133
  tests/shell/004-format-check.sh
134
+ tests/shell/005-lint.sh
135
135
  tests/unit/__init__.py
136
136
  tests/unit/test_deps.py
137
137
  tests/unit/test_format.py
138
+ tests/unit/test_lint_csv.py
138
139
  tests/unit/test_paths.py
139
140
  tests/unit/test_utils.py
140
141
  tests/unit/test_version.py
@@ -5,6 +5,7 @@ Currently implemented for:
5
5
  - *.cf (policy files)
6
6
  - cfbs.json (CFEngine Build project files)
7
7
  - *.json (basic JSON syntax checking)
8
+ - *.csv (basic CSV syntax + RFC 4180 CRLF record terminator check)
8
9
 
9
10
  This is performed in 3 steps:
10
11
  1. Parsing - Read the .cf files and convert them into syntax trees
@@ -38,9 +39,10 @@ from tree_sitter import Language, Node, Parser, Tree
38
39
  from cfbs.validate import validate_config
39
40
  from cfbs.cfbs_config import CFBSConfig
40
41
  from cfbs.utils import find
42
+ from cfengine_cli.lint_csv import check_csv_file
41
43
  from cfengine_cli.utils import UserError
42
44
 
43
- LINT_EXTENSIONS = (".cf", ".cf.sub", ".json")
45
+ LINT_EXTENSIONS = (".cf", ".cf.sub", ".json", ".csv")
44
46
  DEFAULT_NAMESPACE = "default"
45
47
  VARS_TYPES = {
46
48
  "data",
@@ -50,6 +52,7 @@ VARS_TYPES = {
50
52
  "rlist",
51
53
  "slist",
52
54
  "string",
55
+ "str", # deprecated shorthand for string
53
56
  }
54
57
  PROMISE_BLOCK_ATTRIBUTES = ("path", "interpreter")
55
58
 
@@ -583,7 +586,7 @@ def _lint_promise_guard(
583
586
  """Check that a promise type guard (e.g. `vars:`) for deprecation or unknown type."""
584
587
  assert _text(node) and len(_text(node)) > 1 and _text(node)[-1] == ":"
585
588
  promise_type = _text(node)[0:-1]
586
- if promise_type in syntax_data.DEPRECATED_PROMISE_TYPES:
589
+ if state.strict and promise_type in syntax_data.DEPRECATED_PROMISE_TYPES:
587
590
  raise ValidationError(
588
591
  f"Deprecation: Promise type '{promise_type}' is deprecated {location}",
589
592
  node,
@@ -608,16 +611,33 @@ def _lint_block_type(node: Node, state: State, location: str, syntax_data: Synta
608
611
  f"Error: Bundle type must be one of ({', '.join(syntax_data.BUILTIN_BUNDLE_TYPES)}), not '{_text(node)}' {location}",
609
612
  node,
610
613
  )
614
+ if node.type == "promise_block_type" and _text(node) != "agent":
615
+ raise ValidationError(
616
+ f"Error: Promise type must be 'agent', not '{_text(node)}' {location}",
617
+ node,
618
+ )
611
619
 
612
620
 
613
621
  def _lint_block_name(node: Node, state: State, location: str, syntax_data: SyntaxData):
614
622
  """Check that a block name follows conventions and doesn't shadow a built-in."""
615
623
  assert node.type in ("bundle_block_name", "body_block_name", "promise_block_name")
616
624
 
617
- if node.type == "bundle_block_name" and _text(node) != _text(node).lower():
625
+ if (
626
+ state.strict
627
+ and node.type == "bundle_block_name"
628
+ and _text(node) != _text(node).lower()
629
+ ):
618
630
  raise ValidationError(
619
631
  f"Convention: Bundle name should be lowercase {location}", node
620
632
  )
633
+ if (
634
+ state.strict
635
+ and node.type == "body_block_name"
636
+ and _text(node) != _text(node).lower()
637
+ ):
638
+ raise ValidationError(
639
+ f"Convention: Body name should be lowercase {location}", node
640
+ )
621
641
  if node.type == "promise_block_name" and _text(node) != _text(node).lower():
622
642
  raise ValidationError(
623
643
  f"Convention: Promise type should be lowercase {location}", node
@@ -763,11 +783,17 @@ def _lint_attribute_name(
763
783
  """Check an attribute name for deprecations and validity according to the
764
784
  surrounding promise type."""
765
785
  assert node.type == "attribute_name"
766
- if _text(node) == "ifvarclass":
786
+ attribute_name = _text(node)
787
+ assert attribute_name == state.attribute_name
788
+ if state.strict and state.promise_type == "vars" and attribute_name == "str":
789
+ raise ValidationError(
790
+ f"Deprecation: Use 'string' instead of 'str' {location}", node
791
+ )
792
+ if state.strict and attribute_name == "ifvarclass":
767
793
  raise ValidationError(
768
794
  f"Deprecation: Use 'if' instead of 'ifvarclass' {location}", node
769
795
  )
770
- if state.promise_type and state.attribute_name:
796
+ if state.promise_type and attribute_name:
771
797
  promise_type_data = syntax_data.BUILTIN_PROMISE_TYPES.get(
772
798
  state.promise_type, {}
773
799
  )
@@ -775,17 +801,17 @@ def _lint_attribute_name(
775
801
  # Custom promise type - we cannot validate attribute name here.
776
802
  return
777
803
  promise_type_attrs = promise_type_data.get("attributes", {})
778
- if state.attribute_name not in promise_type_attrs:
804
+ if attribute_name not in promise_type_attrs:
779
805
  raise ValidationError(
780
- f"Error: Invalid attribute '{state.attribute_name}' for promise type '{state.promise_type}' {location}",
806
+ f"Error: Invalid attribute '{attribute_name}' for promise type '{state.promise_type}' {location}",
781
807
  node,
782
808
  )
783
- if state.block_keyword == "promise" and state.attribute_name not in (
809
+ if state.block_keyword == "promise" and attribute_name not in (
784
810
  None,
785
811
  *PROMISE_BLOCK_ATTRIBUTES,
786
812
  ):
787
813
  raise ValidationError(
788
- f"Error: Invalid attribute name '{state.attribute_name}' in '{state.block_name}' custom promise type definition {location}",
814
+ f"Error: Invalid attribute name '{attribute_name}' in '{state.block_name}' custom promise type definition {location}",
789
815
  node,
790
816
  )
791
817
 
@@ -1167,6 +1193,9 @@ def _lint_main(
1167
1193
  if filename.endswith(".json"):
1168
1194
  errors += _lint_json_selector(filename)
1169
1195
  continue
1196
+ if filename.endswith(".csv"):
1197
+ errors += _lint_csv(filename)
1198
+ continue
1170
1199
  assert filename.endswith((".cf", ".cf.sub"))
1171
1200
  policy_file = PolicyFile(filename, snippet)
1172
1201
  r = _check_syntax(policy_file, state)
@@ -1304,6 +1333,19 @@ def _lint_json_selector(file: str) -> int:
1304
1333
  return _lint_json_plain(file)
1305
1334
 
1306
1335
 
1336
+ def _lint_csv(filename: str) -> int:
1337
+ """Lint a CSV file: check that csv parses, and that record terminators
1338
+ are CRLF (per RFC 4180)."""
1339
+ assert os.path.isfile(filename)
1340
+ problem = check_csv_file(filename)
1341
+ r = 0
1342
+ if problem is not None:
1343
+ print(f"{filename}: {problem}")
1344
+ r = 1
1345
+ print(_pass_fail_filename(filename, r))
1346
+ return r
1347
+
1348
+
1307
1349
  # ---------------------------------------------------------------------------
1308
1350
  # Syntax error detection (used by both linter and formatter)
1309
1351
  # ---------------------------------------------------------------------------
@@ -0,0 +1,52 @@
1
+ """CSV file validation per RFC 4180.
2
+
3
+ The grammar in RFC 4180 mandates CRLF between records. Bare \\r or \\n
4
+ outside of quoted fields is not valid. Inside quoted fields, \\r and \\n
5
+ are allowed as field content.
6
+ """
7
+
8
+ import csv
9
+
10
+
11
+ def check_csv_record_terminators(raw: str) -> str | None:
12
+ """Check that all record terminators in a CSV string are CRLF.
13
+
14
+ Returns None if all record terminators are CRLF, otherwise a short
15
+ description of the problem.
16
+ """
17
+ in_quotes = False
18
+ _prev = None
19
+ prev = None
20
+ for current in raw:
21
+ prev = _prev
22
+ _prev = current
23
+ if current == '"':
24
+ in_quotes = not in_quotes
25
+ continue
26
+ if in_quotes:
27
+ continue
28
+ if current == "\n" and prev != "\r":
29
+ return "bare LF outside quoted field"
30
+ if prev == "\r" and current != "\n":
31
+ return "bare CR outside quoted field"
32
+ if _prev == "\r" and not in_quotes:
33
+ return "bare CR outside quoted field"
34
+ return None
35
+
36
+
37
+ def check_csv_file(filename: str) -> str | None:
38
+ """Check a CSV file: parses, has at least one non-empty record, and uses
39
+ CRLF record terminators.
40
+
41
+ Returns None if valid, otherwise a short description of the problem.
42
+ """
43
+ try:
44
+ with open(filename, newline="") as f:
45
+ raw = f.read()
46
+ with open(filename, newline="") as f:
47
+ rows = list(csv.reader(f, strict=True))
48
+ except (OSError, csv.Error) as e:
49
+ return str(e)
50
+ if not any(rows):
51
+ return "no records"
52
+ return check_csv_record_terminators(raw)
@@ -0,0 +1,17 @@
1
+
2
+ {
3
+ defaults:
4
+ ^-------^
5
+ Deprecation: Promise type 'defaults' is deprecated at tests/lint/002_deprecations.x.cf:3:3
6
+
7
+ vars:
8
+ "x" str => "value";
9
+ ^-^
10
+ Deprecation: Use 'string' instead of 'str' at tests/lint/002_deprecations.x.cf:6:9
11
+
12
+ "Hello, CFEngine"
13
+ ifvarclass => "cfengine";
14
+ ^--------^
15
+ Deprecation: Use 'if' instead of 'ifvarclass' at tests/lint/002_deprecations.x.cf:9:7
16
+ FAIL: tests/lint/002_deprecations.x.cf (3 errors)
17
+ Failure, 3 errors in total.
@@ -1,5 +1,9 @@
1
1
  bundle agent main
2
2
  {
3
+ defaults:
4
+ "x" string => "value";
5
+ vars:
6
+ "x" str => "value";
3
7
  reports:
4
8
  "Hello, CFEngine"
5
9
  ifvarclass => "cfengine";
@@ -0,0 +1,16 @@
1
+ bundle agent my_bundle
2
+ {
3
+ reports:
4
+ "Hello";
5
+ }
6
+
7
+ body perms my_body
8
+ {
9
+ owners => { "root" };
10
+ }
11
+
12
+ promise agent my_promise_type
13
+ {
14
+ path => "/bin/true";
15
+ interpreter => "/bin/bash";
16
+ }
@@ -0,0 +1,16 @@
1
+
2
+ bundle agent MyBundle
3
+ ^------^
4
+ Convention: Bundle name should be lowercase at tests/lint/003_name_lowercase.x.cf:1:14
5
+
6
+
7
+ body perms MyBody
8
+ ^----^
9
+ Convention: Body name should be lowercase at tests/lint/003_name_lowercase.x.cf:7:12
10
+
11
+
12
+ promise agent MyPromiseType
13
+ ^-----------^
14
+ Convention: Promise type should be lowercase at tests/lint/003_name_lowercase.x.cf:12:15
15
+ FAIL: tests/lint/003_name_lowercase.x.cf (3 errors)
16
+ Failure, 3 errors in total.
@@ -0,0 +1,16 @@
1
+ bundle agent MyBundle
2
+ {
3
+ reports:
4
+ "Hello";
5
+ }
6
+
7
+ body perms MyBody
8
+ {
9
+ owners => { "root" };
10
+ }
11
+
12
+ promise agent MyPromiseType
13
+ {
14
+ path => "/bin/true";
15
+ interpreter => "/bin/bash";
16
+ }
@@ -0,0 +1,11 @@
1
+ bundle common my_bundle
2
+ {
3
+ vars:
4
+ "x" string => "value";
5
+ }
6
+
7
+ promise agent my_promise_type
8
+ {
9
+ path => "/bin/true";
10
+ interpreter => "/bin/bash";
11
+ }
@@ -0,0 +1,11 @@
1
+
2
+ bundle notavalidtype my_bundle
3
+ ^-----------^
4
+ Error: Bundle type must be one of (agent, common, edit_line, edit_xml, monitor, server), not 'notavalidtype' at tests/lint/004_block_type.x.cf:1:8
5
+
6
+
7
+ promise server my_promise_type
8
+ ^----^
9
+ Error: Promise type must be 'agent', not 'server' at tests/lint/004_block_type.x.cf:7:9
10
+ FAIL: tests/lint/004_block_type.x.cf (2 errors)
11
+ Failure, 2 errors in total.
@@ -0,0 +1,11 @@
1
+ bundle notavalidtype my_bundle
2
+ {
3
+ reports:
4
+ "Hello";
5
+ }
6
+
7
+ promise server my_promise_type
8
+ {
9
+ path => "/bin/true";
10
+ interpreter => "/bin/bash";
11
+ }
@@ -0,0 +1,7 @@
1
+
2
+ {
3
+ reports
4
+ ^-----^
5
+ Error: Syntax error at tests/lint/005_syntax_error.x.cf:3:3
6
+ FAIL: tests/lint/005_syntax_error.x.cf (1 error)
7
+ Failure, 1 error in total.
@@ -0,0 +1,3 @@
1
+ Error: Empty policy file 'tests/lint/006_empty_file.x.cf'
2
+ FAIL: tests/lint/006_empty_file.x.cf (1 error)
3
+ Failure, 1 error in total.
@@ -2,6 +2,6 @@
2
2
  methods:
3
3
  "x" usebundle => default:target("arg");
4
4
  ^------------^
5
- Error: Call to unknown bundle 'default:target' at tests/lint/008_namespace.x.cf:15:22
6
- FAIL: tests/lint/008_namespace.x.cf (1 error)
5
+ Error: Call to unknown bundle 'default:target' at tests/lint/007_namespace.x.cf:15:22
6
+ FAIL: tests/lint/007_namespace.x.cf (1 error)
7
7
  Failure, 1 error in total.
@@ -1,6 +1,6 @@
1
1
 
2
2
  bundle agent isvariable
3
3
  ^--------^
4
- Error: Bundle 'isvariable' conflicts with built-in function with the same name at tests/lint/009_bundle_shadows_function.x.cf:1:14
5
- FAIL: tests/lint/009_bundle_shadows_function.x.cf (1 error)
4
+ Error: Bundle 'isvariable' conflicts with built-in function with the same name at tests/lint/008_bundle_shadows_function.x.cf:1:14
5
+ FAIL: tests/lint/008_bundle_shadows_function.x.cf (1 error)
6
6
  Failure, 1 error in total.
@@ -2,11 +2,11 @@
2
2
  vars:
3
3
  "x" string => target("arg");
4
4
  ^----^
5
- Error: Call to unknown function 'target' inside 'vars'-promise at tests/lint/010_unknown_function_inside_vars.x.cf:16:19
5
+ Error: Call to unknown function 'target' inside 'vars'-promise at tests/lint/009_unknown_function_inside_vars.x.cf:16:19
6
6
 
7
7
  "y"
8
8
  classes => isvariable("arg"),
9
9
  ^--------^
10
- Error: 'isvariable' is not a defined body. Only bodies may be called with 'classes' at tests/lint/010_unknown_function_inside_vars.x.cf:18:18
11
- FAIL: tests/lint/010_unknown_function_inside_vars.x.cf (2 errors)
10
+ Error: 'isvariable' is not a defined body. Only bodies may be called with 'classes' at tests/lint/009_unknown_function_inside_vars.x.cf:18:18
11
+ FAIL: tests/lint/009_unknown_function_inside_vars.x.cf (2 errors)
12
12
  Failure, 2 errors in total.
@@ -2,11 +2,11 @@
2
2
  policy => "free",
3
3
  real => "0.5";
4
4
  ^--^
5
- Error: Mutually exclusive attribute values (slist, int, real) for a single promiser inside vars-promise at tests/lint/011_mutually_exclusive_types_vars.x.cf:4:5
5
+ Error: Mutually exclusive attribute values (slist, int, real) for a single promiser inside vars-promise at tests/lint/010_mutually_exclusive_types_vars.x.cf:4:5
6
6
 
7
7
 
8
8
  "missing-error";
9
9
  ^--------------^
10
- Error: Missing value for vars promise "missing-error" at tests/lint/011_mutually_exclusive_types_vars.x.cf:16:5
11
- FAIL: tests/lint/011_mutually_exclusive_types_vars.x.cf (2 errors)
10
+ Error: Missing value for vars promise "missing-error" at tests/lint/010_mutually_exclusive_types_vars.x.cf:16:5
11
+ FAIL: tests/lint/010_mutually_exclusive_types_vars.x.cf (2 errors)
12
12
  Failure, 2 errors in total.
@@ -2,11 +2,11 @@
2
2
  path => "/var/cfengine/inputs/modules/promises/git.py";
3
3
  blah => "something";
4
4
  ^--^
5
- Error: Invalid attribute name 'blah' in 'git' custom promise type definition at tests/lint/012_invalid_attributes.x.cf:5:3
5
+ Error: Invalid attribute name 'blah' in 'git' custom promise type definition at tests/lint/011_invalid_attributes.x.cf:5:3
6
6
 
7
7
  slist => {},
8
8
  bar => "";
9
9
  ^-^
10
- Error: Invalid attribute 'bar' for promise type 'vars' at tests/lint/012_invalid_attributes.x.cf:12:7
11
- FAIL: tests/lint/012_invalid_attributes.x.cf (2 errors)
10
+ Error: Invalid attribute 'bar' for promise type 'vars' at tests/lint/011_invalid_attributes.x.cf:12:7
11
+ FAIL: tests/lint/011_invalid_attributes.x.cf (2 errors)
12
12
  Failure, 2 errors in total.
@@ -2,11 +2,11 @@
2
2
  "string1"
3
3
  string => canonify();
4
4
  ^--------^
5
- Error: Expected 1 arguments, received 0 for function 'canonify' at tests/lint/013_function_call_arg_count.x.cf:5:15
5
+ Error: Expected 1 arguments, received 0 for function 'canonify' at tests/lint/012_function_call_arg_count.x.cf:5:15
6
6
 
7
7
  "string3"
8
8
  string => canonify("test", "test");
9
9
  ^----------------------^
10
- Error: Expected 1 arguments, received 2 for function 'canonify' at tests/lint/013_function_call_arg_count.x.cf:9:15
11
- FAIL: tests/lint/013_function_call_arg_count.x.cf (2 errors)
10
+ Error: Expected 1 arguments, received 2 for function 'canonify' at tests/lint/012_function_call_arg_count.x.cf:9:15
11
+ FAIL: tests/lint/012_function_call_arg_count.x.cf (2 errors)
12
12
  Failure, 2 errors in total.
@@ -2,19 +2,19 @@
2
2
  create => "true",
3
3
  perms => mog("644");
4
4
  ^--------^
5
- Error: Expected 3 arguments, received 1 for body 'mog' at tests/lint/014_num_args_body.x.cf:13:16
6
- Hint: The body 'mog' is defined at tests/lint/014_num_args_body.x.cf:1:12
5
+ Error: Expected 3 arguments, received 1 for body 'mog' at tests/lint/013_num_args_body.x.cf:13:16
6
+ Hint: The body 'mog' is defined at tests/lint/013_num_args_body.x.cf:1:12
7
7
 
8
8
  create => "true",
9
9
  perms => mog("644", "root");
10
10
  ^----------------^
11
- Error: Expected 3 arguments, received 2 for body 'mog' at tests/lint/014_num_args_body.x.cf:16:16
12
- Hint: The body 'mog' is defined at tests/lint/014_num_args_body.x.cf:1:12
11
+ Error: Expected 3 arguments, received 2 for body 'mog' at tests/lint/013_num_args_body.x.cf:16:16
12
+ Hint: The body 'mog' is defined at tests/lint/013_num_args_body.x.cf:1:12
13
13
 
14
14
  create => "true",
15
15
  perms => mog("644", "root", "root", "root");
16
16
  ^--------------------------------^
17
- Error: Expected 3 arguments, received 4 for body 'mog' at tests/lint/014_num_args_body.x.cf:22:16
18
- Hint: The body 'mog' is defined at tests/lint/014_num_args_body.x.cf:1:12
19
- FAIL: tests/lint/014_num_args_body.x.cf (3 errors)
17
+ Error: Expected 3 arguments, received 4 for body 'mog' at tests/lint/013_num_args_body.x.cf:22:16
18
+ Hint: The body 'mog' is defined at tests/lint/013_num_args_body.x.cf:1:12
19
+ FAIL: tests/lint/013_num_args_body.x.cf (3 errors)
20
20
  Failure, 3 errors in total.