cfengine 0.13.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 (168) hide show
  1. cfengine-0.15.0/.github/workflows/lint-policy-in-other-repos.yml +47 -0
  2. cfengine-0.15.0/.github/workflows/make-check.yml +51 -0
  3. cfengine-0.15.0/.github/workflows/update-syntax-description.yml +69 -0
  4. cfengine-0.15.0/.python-version +1 -0
  5. cfengine-0.15.0/CLAUDE.md +51 -0
  6. {cfengine-0.13.0 → cfengine-0.15.0}/HACKING.md +6 -6
  7. cfengine-0.15.0/Makefile +26 -0
  8. {cfengine-0.13.0 → cfengine-0.15.0}/PKG-INFO +2 -2
  9. {cfengine-0.13.0 → cfengine-0.15.0}/pyproject.toml +4 -1
  10. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine.egg-info/PKG-INFO +2 -2
  11. cfengine-0.15.0/src/cfengine.egg-info/SOURCES.txt +141 -0
  12. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine.egg-info/requires.txt +1 -1
  13. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/commands.py +43 -23
  14. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/deptool.py +2 -2
  15. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/dev.py +18 -26
  16. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/docs.py +19 -23
  17. cfengine-0.15.0/src/cfengine_cli/format.py +901 -0
  18. cfengine-0.15.0/src/cfengine_cli/lint.py +1450 -0
  19. cfengine-0.15.0/src/cfengine_cli/lint_csv.py +52 -0
  20. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/main.py +8 -5
  21. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/analyze.py +11 -17
  22. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/download.py +1 -1
  23. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_release_information.py +53 -22
  24. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/profile.py +1 -1
  25. cfengine-0.15.0/src/cfengine_cli/syntax-description.json +10343 -0
  26. cfengine-0.15.0/src/cfengine_cli/syntax_tree.py +42 -0
  27. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/002_basics.expected.cf +8 -4
  28. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/002_basics.input.cf +7 -2
  29. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/003_wrapping.expected.cf +33 -7
  30. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/003_wrapping.input.cf +29 -3
  31. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/004_comments.expected.cf +20 -0
  32. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/004_comments.input.cf +18 -0
  33. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/005_bundle_comments.expected.cf +5 -0
  34. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/005_bundle_comments.input.cf +5 -0
  35. cfengine-0.15.0/tests/format/007_class_guarded_empty_lines.expected.cf +9 -0
  36. cfengine-0.15.0/tests/format/008_long_string.expected.cf +6 -0
  37. cfengine-0.15.0/tests/format/008_long_string.input.cf +5 -0
  38. cfengine-0.15.0/tests/format/009_single_line.expected.cf +58 -0
  39. cfengine-0.15.0/tests/format/009_single_line.input.cf +76 -0
  40. cfengine-0.15.0/tests/format/010_stakeholder.expected.cf +119 -0
  41. cfengine-0.15.0/tests/format/010_stakeholder.input.cf +99 -0
  42. cfengine-0.15.0/tests/format/011_macros.expected.cf +192 -0
  43. cfengine-0.15.0/tests/format/011_macros.input.cf +182 -0
  44. cfengine-0.15.0/tests/format/011_promises.expected.cf +516 -0
  45. cfengine-0.15.0/tests/format/011_promises.input.cf +409 -0
  46. cfengine-0.15.0/tests/lint/002_deprecations.expected.txt +17 -0
  47. cfengine-0.13.0/tests/lint/002_ifvarclass.x.cf → cfengine-0.15.0/tests/lint/002_deprecations.x.cf +4 -0
  48. cfengine-0.15.0/tests/lint/003_name_lowercase.cf +16 -0
  49. cfengine-0.15.0/tests/lint/003_name_lowercase.expected.txt +16 -0
  50. cfengine-0.15.0/tests/lint/003_name_lowercase.x.cf +16 -0
  51. cfengine-0.15.0/tests/lint/004_block_type.cf +11 -0
  52. cfengine-0.15.0/tests/lint/004_block_type.expected.txt +11 -0
  53. cfengine-0.15.0/tests/lint/004_block_type.x.cf +11 -0
  54. cfengine-0.15.0/tests/lint/005_syntax_error.expected.txt +7 -0
  55. cfengine-0.15.0/tests/lint/006_empty_file.expected.txt +3 -0
  56. cfengine-0.13.0/tests/lint/008_namespace.x.cf → cfengine-0.15.0/tests/lint/007_namespace.cf +2 -2
  57. cfengine-0.15.0/tests/lint/007_namespace.expected.txt +7 -0
  58. cfengine-0.13.0/tests/lint/008_namespace.cf → cfengine-0.15.0/tests/lint/007_namespace.x.cf +2 -2
  59. cfengine-0.15.0/tests/lint/008_bundle_shadows_function.cf +5 -0
  60. cfengine-0.15.0/tests/lint/008_bundle_shadows_function.expected.txt +6 -0
  61. cfengine-0.15.0/tests/lint/008_bundle_shadows_function.x.cf +5 -0
  62. cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.cf +24 -0
  63. cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.expected.txt +12 -0
  64. cfengine-0.15.0/tests/lint/009_unknown_function_inside_vars.x.cf +22 -0
  65. cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.cf +14 -0
  66. cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.expected.txt +12 -0
  67. cfengine-0.15.0/tests/lint/010_mutually_exclusive_types_vars.x.cf +17 -0
  68. cfengine-0.15.0/tests/lint/011_invalid_attributes.expected.txt +12 -0
  69. cfengine-0.15.0/tests/lint/011_invalid_attributes.x.cf +13 -0
  70. cfengine-0.15.0/tests/lint/012_function_call_arg_count.cf +8 -0
  71. cfengine-0.15.0/tests/lint/012_function_call_arg_count.expected.txt +12 -0
  72. cfengine-0.15.0/tests/lint/012_function_call_arg_count.x.cf +14 -0
  73. cfengine-0.15.0/tests/lint/013_num_args_body.expected.txt +20 -0
  74. cfengine-0.15.0/tests/lint/013_num_args_body.x.cf +24 -0
  75. cfengine-0.15.0/tests/lint/013_num_args_bundle.expected.txt +20 -0
  76. cfengine-0.15.0/tests/lint/013_num_args_bundle.x.cf +17 -0
  77. cfengine-0.15.0/tests/lint/013_num_args_bundle_body.cf +11 -0
  78. cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.cf +16 -0
  79. cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.expected.txt +12 -0
  80. cfengine-0.15.0/tests/lint/014_variadic_func_arg_count.x.cf +18 -0
  81. cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.cf +25 -0
  82. cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.expected.txt +14 -0
  83. cfengine-0.15.0/tests/lint/015_macro_multi_def_bundle.x.cf +25 -0
  84. cfengine-0.15.0/tests/lint/016_half_promises.cf +12 -0
  85. cfengine-0.15.0/tests/lint/016_half_promises.expected.txt +17 -0
  86. cfengine-0.15.0/tests/lint/016_half_promises.x.cf +29 -0
  87. cfengine-0.15.0/tests/lint/017_implies_body.cf +12 -0
  88. cfengine-0.15.0/tests/lint/017_implies_body.expected.txt +38 -0
  89. cfengine-0.15.0/tests/lint/017_implies_body.x.cf +31 -0
  90. cfengine-0.15.0/tests/lint/018_nested_calls.cf +22 -0
  91. cfengine-0.15.0/tests/lint/018_nested_calls.expected.txt +22 -0
  92. cfengine-0.15.0/tests/lint/018_nested_calls.x.cf +24 -0
  93. cfengine-0.15.0/tests/lint/019_bundle_name_expansion.cf +15 -0
  94. cfengine-0.15.0/tests/shell/004-format-check.sh +67 -0
  95. cfengine-0.15.0/tests/shell/005-lint.sh +46 -0
  96. cfengine-0.15.0/tests/unit/test_format.py +514 -0
  97. cfengine-0.15.0/tests/unit/test_lint_csv.py +73 -0
  98. cfengine-0.15.0/uv.lock +474 -0
  99. cfengine-0.13.0/.github/workflows/format.yml +0 -61
  100. cfengine-0.13.0/.github/workflows/lint.yml +0 -44
  101. cfengine-0.13.0/.github/workflows/test.yml +0 -53
  102. cfengine-0.13.0/.python-version +0 -1
  103. cfengine-0.13.0/Makefile +0 -22
  104. cfengine-0.13.0/src/cfengine.egg-info/SOURCES.txt +0 -93
  105. cfengine-0.13.0/src/cfengine_cli/format.py +0 -407
  106. cfengine-0.13.0/src/cfengine_cli/lint.py +0 -885
  107. cfengine-0.13.0/src/cfengine_cli/policy_language.py +0 -239
  108. cfengine-0.13.0/tests/format/007_class_guarded_empty_lines.expected.cf +0 -11
  109. cfengine-0.13.0/tests/lint/002_ifvarclass.expected.txt +0 -7
  110. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.cf +0 -5
  111. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.expected.txt +0 -7
  112. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.x.cf +0 -5
  113. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.cf +0 -5
  114. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.expected.txt +0 -6
  115. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.x.cf +0 -5
  116. cfengine-0.13.0/tests/lint/005_bundle_type.cf +0 -5
  117. cfengine-0.13.0/tests/lint/005_bundle_type.expected.txt +0 -6
  118. cfengine-0.13.0/tests/lint/005_bundle_type.x.cf +0 -5
  119. cfengine-0.13.0/tests/lint/006_syntax_error.expected.txt +0 -7
  120. cfengine-0.13.0/tests/lint/007_empty_file.expected.txt +0 -3
  121. cfengine-0.13.0/tests/lint/008_namespace.expected.txt +0 -7
  122. cfengine-0.13.0/tests/unit/test_format.py +0 -70
  123. cfengine-0.13.0/uv.lock +0 -474
  124. {cfengine-0.13.0 → cfengine-0.15.0}/.github/dependabot.yml +0 -0
  125. {cfengine-0.13.0 → cfengine-0.15.0}/.github/workflows/pypi-publish.yml +0 -0
  126. {cfengine-0.13.0 → cfengine-0.15.0}/.gitignore +0 -0
  127. {cfengine-0.13.0 → cfengine-0.15.0}/LICENSE +0 -0
  128. {cfengine-0.13.0 → cfengine-0.15.0}/README.md +0 -0
  129. {cfengine-0.13.0 → cfengine-0.15.0}/ci/01-install.sh +0 -0
  130. {cfengine-0.13.0 → cfengine-0.15.0}/ci/02-safe-tests.sh +0 -0
  131. {cfengine-0.13.0 → cfengine-0.15.0}/ci/03-unsafe-tests.sh +0 -0
  132. {cfengine-0.13.0 → cfengine-0.15.0}/setup.cfg +0 -0
  133. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
  134. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine.egg-info/entry_points.txt +0 -0
  135. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine.egg-info/top_level.txt +0 -0
  136. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/__init__.py +0 -0
  137. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/__main__.py +0 -0
  138. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/deptool-README.md +0 -0
  139. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
  140. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
  141. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
  142. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
  143. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
  144. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/paths.py +0 -0
  145. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/shell.py +0 -0
  146. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/utils.py +0 -0
  147. {cfengine-0.13.0 → cfengine-0.15.0}/src/cfengine_cli/version.py +0 -0
  148. {cfengine-0.13.0 → cfengine-0.15.0}/tests/README.md +0 -0
  149. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/001_hello_world.expected.cf +0 -0
  150. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/001_hello_world.input.cf +0 -0
  151. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/006_remove_empty_comments.expected.cf +0 -0
  152. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/006_remove_empty_comments.input.cf +0 -0
  153. {cfengine-0.13.0 → cfengine-0.15.0}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
  154. {cfengine-0.13.0 → cfengine-0.15.0}/tests/lint/001_hello_world.cf +0 -0
  155. /cfengine-0.13.0/tests/lint/006_syntax_error.cf → /cfengine-0.15.0/tests/lint/005_syntax_error.cf +0 -0
  156. /cfengine-0.13.0/tests/lint/006_syntax_error.x.cf → /cfengine-0.15.0/tests/lint/005_syntax_error.x.cf +0 -0
  157. /cfengine-0.13.0/tests/lint/007_empty_file.x.cf → /cfengine-0.15.0/tests/lint/006_empty_file.x.cf +0 -0
  158. {cfengine-0.13.0 → cfengine-0.15.0}/tests/run-format-tests.sh +0 -0
  159. {cfengine-0.13.0 → cfengine-0.15.0}/tests/run-lint-tests.sh +0 -0
  160. {cfengine-0.13.0 → cfengine-0.15.0}/tests/run-shell-tests.sh +0 -0
  161. {cfengine-0.13.0 → cfengine-0.15.0}/tests/shell/001-help.sh +0 -0
  162. {cfengine-0.13.0 → cfengine-0.15.0}/tests/shell/002-version.sh +0 -0
  163. {cfengine-0.13.0 → cfengine-0.15.0}/tests/shell/003-format.sh +0 -0
  164. {cfengine-0.13.0 → cfengine-0.15.0}/tests/unit/__init__.py +0 -0
  165. {cfengine-0.13.0 → cfengine-0.15.0}/tests/unit/test_deps.py +0 -0
  166. {cfengine-0.13.0 → cfengine-0.15.0}/tests/unit/test_paths.py +0 -0
  167. {cfengine-0.13.0 → cfengine-0.15.0}/tests/unit/test_utils.py +0 -0
  168. {cfengine-0.13.0 → cfengine-0.15.0}/tests/unit/test_version.py +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
@@ -0,0 +1,51 @@
1
+ # This workflow installs the necessary dependencies, runs make check, and
2
+ # checks if there are any edits. It should be very similar to what developers
3
+ # are expected to do locally. We want to ensure that all tests pass (make
4
+ # check succeeds) and that there is no additional formatting / untracked
5
+ # files generated.
6
+ #
7
+ # Note that make check is a bit special in this repo, it has some things you
8
+ # might not expect:
9
+ # 1. It doesn't only run tests, it also runs formatters and linters
10
+ # 2. It installs the CFEngine CLI, so that shell tests will work
11
+
12
+ name: Run make check
13
+ on:
14
+ push:
15
+ branches: [main]
16
+ pull_request:
17
+ branches: [main]
18
+ permissions:
19
+ contents: read
20
+ jobs:
21
+ check:
22
+ runs-on: ubuntu-24.04
23
+ strategy:
24
+ fail-fast: true
25
+ matrix:
26
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - name: Set up Python ${{ matrix.python-version }}
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+ - name: Install dependencies
34
+ run: |
35
+ python -m pip install --upgrade pip
36
+ python -m pip install uv
37
+ sudo apt-get install npm
38
+ npm install --global prettier
39
+ - name: Set python version file for uv
40
+ run: |
41
+ echo "${{ matrix.python-version }}" > .python-version
42
+ - name: Run make check
43
+ run: |
44
+ make check
45
+ - name: Reset python version file
46
+ run: |
47
+ git restore .python-version
48
+ - name: See if there are changes
49
+ run: |
50
+ git diff --exit-code
51
+ git ls-files --other --directory --exclude-standard | sed q1
@@ -0,0 +1,69 @@
1
+ name: Update syntax-description
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 7 * * 1" # Run every Monday at 7am UTC
6
+ # | | | | |
7
+ # | | | | day of the week (0-6) (Sunday to Saturday)
8
+ # | | | month (1-12)
9
+ # | | day of the month (1-31)
10
+ # | hour (0-23)
11
+ # minute (0-59)
12
+ workflow_dispatch: # Enables manual trigger
13
+
14
+ jobs:
15
+ update_syntax_desc:
16
+ if: contains(fromJSON('["cfengine","mendersoftware","NorthernTechHQ"]'), github.repository_owner)
17
+ name: Update syntax-description
18
+ runs-on: ubuntu-24.04
19
+ permissions:
20
+ contents: write
21
+ pull-requests: write
22
+ steps:
23
+ - name: Checks-out repository
24
+ uses: actions/checkout@v4
25
+ with:
26
+ ref: "main"
27
+ - name: Set up Python 3.12
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+ - name: Install dependencies
32
+ run: |
33
+ python -m pip install --upgrade pip
34
+ python -m pip install cf-remote cfengine
35
+ - name: Install cfengine
36
+ run: |
37
+ cf-remote --version master download --edition community ubuntu24 amd64 hub
38
+ sudo dpkg -i ~/.cfengine/cf-remote/packages/cfengine-community*.deb
39
+ - name: Extract new syntax-description
40
+ run: |
41
+ (
42
+ sudo cf-promises --syntax-description json
43
+ ) > new.json
44
+ cfengine format new.json
45
+ - name: Set Git user
46
+ run: |
47
+ git config user.name 'github-actions[bot]'
48
+ git config user.email 'github-actions[bot]@users.noreply.github.com'
49
+ - name: Update contents of syntax-description
50
+ run: |
51
+ if ! cmp -s new.json ./src/cfengine_cli/syntax-description.json; then
52
+ cat new.json > ./src/cfengine_cli/syntax-description.json
53
+ echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
54
+ rm new.json
55
+ fi
56
+ - name: Create Pull Request
57
+ if: env.CHANGES_DETECTED == 'true'
58
+ uses: cfengine/create-pull-request@v6
59
+ with:
60
+ title: Updated syntax-description.json
61
+ body: Automated update to syntax-description.json [the `update-syntax-description` workflow](https://github.com/cfengine/cfengine-cli/tree/main/.github/workflows/update-syntax-description.yml).
62
+ reviewers: |
63
+ simonthalvorsen
64
+ olehermanse
65
+ larsewi
66
+ nickanderson
67
+ craigcomstock
68
+ branch: update-syntax-description
69
+ branch-suffix: timestamp
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,51 @@
1
+ # CFEngine CLI information for LLMs
2
+
3
+ ## Fix the implementation
4
+
5
+ In general, when the prompter asks you to fix the implementation, this means that they have adjusted the tests already and they want you to fix the implementation.
6
+ Typically you should not touch the tests in this case, unless there is something obviously wrong in them, like a typo.
7
+ The first step to identify what is necessary should be to run the tests and see which ones are failing.
8
+
9
+ ## Running tests
10
+
11
+ In general, the main command to run for testing is:
12
+
13
+ ```bash
14
+ make check
15
+ ```
16
+
17
+ This will run all the test suites.
18
+
19
+ ## Running python tools
20
+
21
+ This project uses `uv`.
22
+ That means that you should not run `python`, `python3`, `pip`, `pip3` directly.
23
+ Instead, run the appropriate uv command to ensure we're using the right python and the right dependencies.
24
+
25
+ ## Pointers for the source code
26
+
27
+ When fixing issues, these are usually the files to look at:
28
+
29
+ - The implementation of `cfengine format` is in `src/cfengine_cli/format.py`.
30
+ - The implementation of `cfengine lint` is in `src/cfengine_cli/lint.py`.
31
+
32
+ ## Syntax trees
33
+
34
+ When working on the formatter or the linter, it is often useful to look at the syntax tree of the policy file.
35
+ There is a `dev` subcommand for this:
36
+
37
+ ```bash
38
+ uv run cfengine dev syntax-tree tests/lint/001_hello_world.cf
39
+ ```
40
+
41
+ The command above prints the syntax tree for `tests/lint/001_hello_world.cf` to the terminal (standard output).
42
+
43
+ ## Test suites
44
+
45
+ As mentioned above, the `make check` command runs all the tests.
46
+ We have different suites:
47
+
48
+ - Unit tests in `tests/unit` test individual python functions.
49
+ - Formatting tests in `tests/format` test the formatter (`cfengine format`).
50
+ - Linting tests in `tests/lint` test the linter.
51
+ - Shell tests in `tests/shell` tests various subcommands and the tool as a whole in an end-to-end fashion.
@@ -18,17 +18,17 @@ make format
18
18
 
19
19
  ## Installing from source:
20
20
 
21
- For developers working on CFEngine CLI, it is recommended to install an editable version of the tool:
21
+ For developers working on CFEngine CLI, you can install it globally using pipx:
22
22
 
23
23
  ```bash
24
24
  make install
25
25
  ```
26
26
 
27
- Some of the tests require that you have the CLI installed (they run `cfengine` commands).
27
+ This is optional `make check` and `uv run` work without a global install.
28
28
 
29
29
  ## Running commands without installing
30
30
 
31
- You can also run commands without installing, using `uv`:
31
+ You can run commands without installing globally, using `uv`:
32
32
 
33
33
  ```bash
34
34
  uv run cfengine format
@@ -46,9 +46,9 @@ Running individual test suites:
46
46
 
47
47
  ```bash
48
48
  uv run pytest
49
- bash tests/run-lint-tests.sh
50
- bash tests/run-format-tests.sh
51
- bash tests/run-shell-tests.sh
49
+ uv run bash tests/run-lint-tests.sh
50
+ uv run bash tests/run-format-tests.sh
51
+ uv run bash tests/run-shell-tests.sh
52
52
  ```
53
53
 
54
54
  ## Releasing new versions
@@ -0,0 +1,26 @@
1
+ .PHONY: default format lint install check venv
2
+
3
+ default: check
4
+
5
+ venv:
6
+ uv venv --clear
7
+ uv sync
8
+
9
+ format: venv
10
+ uv tool run black . --target-version py310
11
+ prettier . --write
12
+
13
+ lint: venv
14
+ uv tool run black --check . --fast
15
+ uv tool run flake8 src/ --ignore=E203,W503,E722,E731 --max-complexity=100 --max-line-length=160
16
+ uv tool run pyflakes src/
17
+ uv tool run pyright src/
18
+
19
+ install:
20
+ pipx install --force --editable .
21
+
22
+ check: venv format lint
23
+ uv run pytest
24
+ uv run bash tests/run-lint-tests.sh
25
+ uv run bash tests/run-format-tests.sh
26
+ uv run bash tests/run-shell-tests.sh
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.13.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
@@ -696,7 +696,7 @@ Requires-Python: >=3.10
696
696
  Description-Content-Type: text/markdown
697
697
  Requires-Dist: cf-remote>=0.7.3
698
698
  Requires-Dist: cfbs>=5.5.0
699
- Requires-Dist: tree-sitter-cfengine>=1.1.8
699
+ Requires-Dist: tree-sitter-cfengine>=1.1.12
700
700
  Requires-Dist: tree-sitter>=0.25
701
701
  Requires-Dist: markdown-it-py>=3.0.0
702
702
 
@@ -12,7 +12,7 @@ requires-python = ">=3.10"
12
12
  dependencies = [
13
13
  "cf-remote>=0.7.3",
14
14
  "cfbs>=5.5.0",
15
- "tree-sitter-cfengine>=1.1.8",
15
+ "tree-sitter-cfengine>=1.1.12",
16
16
  "tree-sitter>=0.25",
17
17
  "markdown-it-py>=3.0.0",
18
18
  ]
@@ -40,6 +40,9 @@ cfengine = "cfengine_cli.main:main"
40
40
  [tool.setuptools]
41
41
  license-files = [] # Workaround bug in setuptools https://github.com/astral-sh/uv/issues/9513
42
42
 
43
+ [tool.setuptools.package-data]
44
+ cfengine_cli = ["*.json"] # syntax-description.json
45
+
43
46
  [tool.pyright]
44
47
  include = ["src"]
45
48
  venvPath = "."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.13.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
@@ -696,7 +696,7 @@ Requires-Python: >=3.10
696
696
  Description-Content-Type: text/markdown
697
697
  Requires-Dist: cf-remote>=0.7.3
698
698
  Requires-Dist: cfbs>=5.5.0
699
- Requires-Dist: tree-sitter-cfengine>=1.1.8
699
+ Requires-Dist: tree-sitter-cfengine>=1.1.12
700
700
  Requires-Dist: tree-sitter>=0.25
701
701
  Requires-Dist: markdown-it-py>=3.0.0
702
702
 
@@ -0,0 +1,141 @@
1
+ .gitignore
2
+ .python-version
3
+ CLAUDE.md
4
+ HACKING.md
5
+ LICENSE
6
+ Makefile
7
+ README.md
8
+ pyproject.toml
9
+ uv.lock
10
+ .github/dependabot.yml
11
+ .github/workflows/lint-policy-in-other-repos.yml
12
+ .github/workflows/make-check.yml
13
+ .github/workflows/pypi-publish.yml
14
+ .github/workflows/update-syntax-description.yml
15
+ ci/01-install.sh
16
+ ci/02-safe-tests.sh
17
+ ci/03-unsafe-tests.sh
18
+ src/cfengine.egg-info/PKG-INFO
19
+ src/cfengine.egg-info/SOURCES.txt
20
+ src/cfengine.egg-info/dependency_links.txt
21
+ src/cfengine.egg-info/entry_points.txt
22
+ src/cfengine.egg-info/requires.txt
23
+ src/cfengine.egg-info/top_level.txt
24
+ src/cfengine_cli/__init__.py
25
+ src/cfengine_cli/__main__.py
26
+ src/cfengine_cli/commands.py
27
+ src/cfengine_cli/deptool-README.md
28
+ src/cfengine_cli/deptool.py
29
+ src/cfengine_cli/dev.py
30
+ src/cfengine_cli/docs.py
31
+ src/cfengine_cli/format.py
32
+ src/cfengine_cli/lint.py
33
+ src/cfengine_cli/lint_csv.py
34
+ src/cfengine_cli/main.py
35
+ src/cfengine_cli/paths.py
36
+ src/cfengine_cli/profile.py
37
+ src/cfengine_cli/shell.py
38
+ src/cfengine_cli/syntax-description.json
39
+ src/cfengine_cli/syntax_tree.py
40
+ src/cfengine_cli/utils.py
41
+ src/cfengine_cli/version.py
42
+ src/cfengine_cli/masterfiles/__init__.py
43
+ src/cfengine_cli/masterfiles/analyze.py
44
+ src/cfengine_cli/masterfiles/check_download_matches_git.py
45
+ src/cfengine_cli/masterfiles/download.py
46
+ src/cfengine_cli/masterfiles/generate_git_tags.py
47
+ src/cfengine_cli/masterfiles/generate_release_information.py
48
+ src/cfengine_cli/masterfiles/generate_vcf_download.py
49
+ src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py
50
+ tests/README.md
51
+ tests/run-format-tests.sh
52
+ tests/run-lint-tests.sh
53
+ tests/run-shell-tests.sh
54
+ tests/format/001_hello_world.expected.cf
55
+ tests/format/001_hello_world.input.cf
56
+ tests/format/002_basics.expected.cf
57
+ tests/format/002_basics.input.cf
58
+ tests/format/003_wrapping.expected.cf
59
+ tests/format/003_wrapping.input.cf
60
+ tests/format/004_comments.expected.cf
61
+ tests/format/004_comments.input.cf
62
+ tests/format/005_bundle_comments.expected.cf
63
+ tests/format/005_bundle_comments.input.cf
64
+ tests/format/006_remove_empty_comments.expected.cf
65
+ tests/format/006_remove_empty_comments.input.cf
66
+ tests/format/007_class_guarded_empty_lines.expected.cf
67
+ tests/format/007_class_guarded_empty_lines.input.cf
68
+ tests/format/008_long_string.expected.cf
69
+ tests/format/008_long_string.input.cf
70
+ tests/format/009_single_line.expected.cf
71
+ tests/format/009_single_line.input.cf
72
+ tests/format/010_stakeholder.expected.cf
73
+ tests/format/010_stakeholder.input.cf
74
+ tests/format/011_macros.expected.cf
75
+ tests/format/011_macros.input.cf
76
+ tests/format/011_promises.expected.cf
77
+ tests/format/011_promises.input.cf
78
+ tests/lint/001_hello_world.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
130
+ tests/shell/001-help.sh
131
+ tests/shell/002-version.sh
132
+ tests/shell/003-format.sh
133
+ tests/shell/004-format-check.sh
134
+ tests/shell/005-lint.sh
135
+ tests/unit/__init__.py
136
+ tests/unit/test_deps.py
137
+ tests/unit/test_format.py
138
+ tests/unit/test_lint_csv.py
139
+ tests/unit/test_paths.py
140
+ tests/unit/test_utils.py
141
+ tests/unit/test_version.py
@@ -1,5 +1,5 @@
1
1
  cf-remote>=0.7.3
2
2
  cfbs>=5.5.0
3
- tree-sitter-cfengine>=1.1.8
3
+ tree-sitter-cfengine>=1.1.12
4
4
  tree-sitter>=0.25
5
5
  markdown-it-py>=3.0.0
@@ -4,7 +4,7 @@ import re
4
4
  import json
5
5
  from cfengine_cli.profile import profile_cfengine, generate_callstack
6
6
  from cfengine_cli.dev import dispatch_dev_subcommand
7
- from cfengine_cli.lint import lint_args
7
+ from cfengine_cli.lint import lint_args, PolicySyntaxError
8
8
  from cfengine_cli.shell import user_command
9
9
  from cfengine_cli.paths import bin
10
10
  from cfengine_cli.version import cfengine_cli_version_string
@@ -14,7 +14,6 @@ from cfengine_cli.format import (
14
14
  format_policy_fin_fout,
15
15
  )
16
16
  from cfengine_cli.utils import UserError
17
- from cfbs.utils import find
18
17
  from cfbs.commands import build_command
19
18
  from cf_remote.commands import deploy as deploy_command
20
19
 
@@ -50,34 +49,53 @@ def deploy() -> int:
50
49
  return r
51
50
 
52
51
 
53
- def _format_filename(filename, line_length):
54
- if filename.startswith("./."):
55
- return
52
+ def _format_filename(filename: str, line_length: int, check: bool) -> int:
53
+ """Format a single file.
54
+
55
+ Raises PolicySyntaxError for .cf files with syntax errors."""
56
56
  if filename.endswith(".json"):
57
- format_json_file(filename)
58
- return
57
+ return format_json_file(filename, check)
59
58
  if filename.endswith(".cf"):
60
- format_policy_file(filename, line_length)
61
- return
59
+ return format_policy_file(filename, line_length, check)
62
60
  raise UserError(f"Unrecognized file format: {filename}")
63
61
 
64
62
 
65
- def _format_dirname(directory, line_length):
66
- for filename in find(directory, extension=".json"):
67
- _format_filename(filename, line_length)
68
- for filename in find(directory, extension=".cf"):
69
- _format_filename(filename, line_length)
70
-
71
-
72
- def format(names, line_length) -> int:
63
+ def _format_dirname(directory: str, line_length: int, check: bool) -> int:
64
+ ret = 0
65
+ for root, dirs, files in os.walk(directory):
66
+ # Don't recurse into hidden folders
67
+ dirs[:] = [d for d in dirs if not d.startswith(".")]
68
+ for name in sorted(files):
69
+ if name.startswith("."):
70
+ continue # Hidden files are ignored by default
71
+ if name.endswith(".x.cf") or name.endswith(".input.cf"):
72
+ continue # Test files skipped during directory traversal
73
+ if name.endswith(
74
+ (".input.json", ".jqinput.json", ".x.json", ".expected.json")
75
+ ):
76
+ continue # Test files skipped during directory traversal
77
+ filepath = os.path.join(root, name)
78
+ if name.endswith(".json") or name.endswith(".cf"):
79
+ ret |= _format_filename(filepath, line_length, check)
80
+ return ret
81
+
82
+
83
+ def format(names, line_length, check) -> int:
84
+ try:
85
+ return _format_inner(names, line_length, check)
86
+ except PolicySyntaxError as e:
87
+ print(f"Error: {e}")
88
+ return 1
89
+
90
+
91
+ def _format_inner(names, line_length, check) -> int:
73
92
  if not names:
74
- _format_dirname(".", line_length)
75
- return 0
93
+ return _format_dirname(".", line_length, check)
76
94
  if len(names) == 1 and names[0] == "-":
77
95
  # Special case, format policy file from stdin to stdout
78
- format_policy_fin_fout(sys.stdin, sys.stdout, line_length)
79
- return 0
96
+ return format_policy_fin_fout(sys.stdin, sys.stdout, line_length, check)
80
97
 
98
+ ret = 0
81
99
  for name in names:
82
100
  if name == "-":
83
101
  raise UserError(
@@ -86,11 +104,13 @@ def format(names, line_length) -> int:
86
104
  if not os.path.exists(name):
87
105
  raise UserError(f"{name} does not exist")
88
106
  if os.path.isfile(name):
89
- _format_filename(name, line_length)
107
+ ret |= _format_filename(name, line_length, check)
90
108
  continue
91
109
  if os.path.isdir(name):
92
- _format_dirname(name, line_length)
110
+ ret |= _format_dirname(name, line_length, check)
93
111
  continue
112
+ if check:
113
+ return ret
94
114
  return 0
95
115
 
96
116
 
@@ -8,7 +8,7 @@ import re
8
8
  import subprocess
9
9
  import sys
10
10
 
11
- ACTIVE_BRANCHES = ["3.21.x", "3.24.x", "master"]
11
+ ACTIVE_BRANCHES = ["3.24.x", "3.27.x", "master"]
12
12
 
13
13
  HUMAN_NAME = {
14
14
  "diffutils": "diffutils",
@@ -260,7 +260,7 @@ class DepsReader:
260
260
  # currently only_deps is generator of space-separated deps,
261
261
  # i.e. each item can contain several items, like this:
262
262
  # list(only_deps) = ["lcov", "pthreads-w32 libgnurx"]
263
- # to "flattern" it we first join using spaces and then split on spaces
263
+ # to "flatten" it we first join using spaces and then split on spaces
264
264
  # in the middle we also do some clean-ups
265
265
  only_deps = " ".join(only_deps).replace("libgcc ", "").split(" ")
266
266
  # now only_deps looks like this: ["lcov", "pthreads-w32", "libgnurx"]