cfengine 0.12.2__tar.gz → 0.13.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 (97) hide show
  1. {cfengine-0.12.2 → cfengine-0.13.0}/.github/workflows/test.yml +4 -0
  2. {cfengine-0.12.2 → cfengine-0.13.0}/.gitignore +1 -0
  3. {cfengine-0.12.2 → cfengine-0.13.0}/HACKING.md +47 -51
  4. cfengine-0.13.0/Makefile +22 -0
  5. {cfengine-0.12.2 → cfengine-0.13.0}/PKG-INFO +3 -3
  6. {cfengine-0.12.2 → cfengine-0.13.0}/README.md +2 -2
  7. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/PKG-INFO +3 -3
  8. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/SOURCES.txt +36 -6
  9. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/commands.py +5 -9
  10. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/docs.py +59 -25
  11. cfengine-0.13.0/src/cfengine_cli/format.py +407 -0
  12. cfengine-0.13.0/src/cfengine_cli/lint.py +885 -0
  13. cfengine-0.13.0/tests/README.md +58 -0
  14. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/002_basics.expected.cf +5 -1
  15. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/002_basics.input.cf +3 -0
  16. cfengine-0.13.0/tests/format/005_bundle_comments.expected.cf +49 -0
  17. cfengine-0.13.0/tests/format/005_bundle_comments.input.cf +47 -0
  18. cfengine-0.13.0/tests/format/006_remove_empty_comments.expected.cf +24 -0
  19. cfengine-0.13.0/tests/format/006_remove_empty_comments.input.cf +30 -0
  20. cfengine-0.13.0/tests/format/007_class_guarded_empty_lines.expected.cf +11 -0
  21. cfengine-0.13.0/tests/format/007_class_guarded_empty_lines.input.cf +10 -0
  22. cfengine-0.13.0/tests/lint/001_hello_world.cf +5 -0
  23. cfengine-0.13.0/tests/lint/002_ifvarclass.expected.txt +7 -0
  24. cfengine-0.13.0/tests/lint/002_ifvarclass.x.cf +6 -0
  25. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.cf +5 -0
  26. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.expected.txt +7 -0
  27. cfengine-0.13.0/tests/lint/003_deprecated_promise_type.x.cf +5 -0
  28. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.cf +5 -0
  29. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.expected.txt +6 -0
  30. cfengine-0.13.0/tests/lint/004_bundle_name_lowercase.x.cf +5 -0
  31. cfengine-0.13.0/tests/lint/005_bundle_type.cf +5 -0
  32. cfengine-0.13.0/tests/lint/005_bundle_type.expected.txt +6 -0
  33. cfengine-0.13.0/tests/lint/005_bundle_type.x.cf +5 -0
  34. cfengine-0.13.0/tests/lint/006_syntax_error.cf +5 -0
  35. cfengine-0.13.0/tests/lint/006_syntax_error.expected.txt +7 -0
  36. cfengine-0.13.0/tests/lint/006_syntax_error.x.cf +5 -0
  37. cfengine-0.13.0/tests/lint/007_empty_file.expected.txt +3 -0
  38. cfengine-0.13.0/tests/lint/008_namespace.cf +16 -0
  39. cfengine-0.13.0/tests/lint/008_namespace.expected.txt +7 -0
  40. cfengine-0.13.0/tests/lint/008_namespace.x.cf +16 -0
  41. {cfengine-0.12.2 → cfengine-0.13.0}/tests/run-format-tests.sh +3 -4
  42. cfengine-0.13.0/tests/run-lint-tests.sh +46 -0
  43. {cfengine-0.12.2 → cfengine-0.13.0}/tests/run-shell-tests.sh +2 -1
  44. cfengine-0.13.0/tests/unit/__init__.py +0 -0
  45. cfengine-0.13.0/tests/unit/test_format.py +70 -0
  46. cfengine-0.12.2/src/cfengine_cli/format.py +0 -242
  47. cfengine-0.12.2/src/cfengine_cli/lint.py +0 -399
  48. {cfengine-0.12.2 → cfengine-0.13.0}/.github/dependabot.yml +0 -0
  49. {cfengine-0.12.2 → cfengine-0.13.0}/.github/workflows/format.yml +0 -0
  50. {cfengine-0.12.2 → cfengine-0.13.0}/.github/workflows/lint.yml +0 -0
  51. {cfengine-0.12.2 → cfengine-0.13.0}/.github/workflows/pypi-publish.yml +0 -0
  52. {cfengine-0.12.2 → cfengine-0.13.0}/.python-version +0 -0
  53. {cfengine-0.12.2 → cfengine-0.13.0}/LICENSE +0 -0
  54. {cfengine-0.12.2 → cfengine-0.13.0}/ci/01-install.sh +0 -0
  55. {cfengine-0.12.2 → cfengine-0.13.0}/ci/02-safe-tests.sh +0 -0
  56. {cfengine-0.12.2 → cfengine-0.13.0}/ci/03-unsafe-tests.sh +0 -0
  57. {cfengine-0.12.2 → cfengine-0.13.0}/pyproject.toml +0 -0
  58. {cfengine-0.12.2 → cfengine-0.13.0}/setup.cfg +0 -0
  59. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
  60. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/entry_points.txt +0 -0
  61. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/requires.txt +0 -0
  62. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine.egg-info/top_level.txt +0 -0
  63. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/__init__.py +0 -0
  64. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/__main__.py +0 -0
  65. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/deptool-README.md +0 -0
  66. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/deptool.py +0 -0
  67. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/dev.py +0 -0
  68. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/main.py +0 -0
  69. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
  70. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/analyze.py +0 -0
  71. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
  72. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/download.py +0 -0
  73. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
  74. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
  75. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
  76. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
  77. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/paths.py +0 -0
  78. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/policy_language.py +0 -0
  79. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/profile.py +0 -0
  80. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/shell.py +0 -0
  81. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/utils.py +0 -0
  82. {cfengine-0.12.2 → cfengine-0.13.0}/src/cfengine_cli/version.py +0 -0
  83. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/001_hello_world.expected.cf +0 -0
  84. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/001_hello_world.input.cf +0 -0
  85. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/003_wrapping.expected.cf +0 -0
  86. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/003_wrapping.input.cf +0 -0
  87. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/004_comments.expected.cf +0 -0
  88. {cfengine-0.12.2 → cfengine-0.13.0}/tests/format/004_comments.input.cf +0 -0
  89. /cfengine-0.12.2/tests/__init__.py → /cfengine-0.13.0/tests/lint/007_empty_file.x.cf +0 -0
  90. {cfengine-0.12.2 → cfengine-0.13.0}/tests/shell/001-help.sh +0 -0
  91. {cfengine-0.12.2 → cfengine-0.13.0}/tests/shell/002-version.sh +0 -0
  92. {cfengine-0.12.2 → cfengine-0.13.0}/tests/shell/003-format.sh +0 -0
  93. {cfengine-0.12.2/tests → cfengine-0.13.0/tests/unit}/test_deps.py +0 -0
  94. {cfengine-0.12.2/tests → cfengine-0.13.0/tests/unit}/test_paths.py +0 -0
  95. {cfengine-0.12.2/tests → cfengine-0.13.0/tests/unit}/test_utils.py +0 -0
  96. {cfengine-0.12.2/tests → cfengine-0.13.0/tests/unit}/test_version.py +0 -0
  97. {cfengine-0.12.2 → cfengine-0.13.0}/uv.lock +0 -0
@@ -47,3 +47,7 @@ jobs:
47
47
  run: |
48
48
  source .venv/bin/activate
49
49
  bash tests/run-format-tests.sh
50
+ - name: Lint tests
51
+ run: |
52
+ source .venv/bin/activate
53
+ bash tests/run-lint-tests.sh
@@ -11,6 +11,7 @@ __pycache__
11
11
  /tmp/
12
12
  *.log
13
13
  *.output.cf
14
+ *.output.txt
14
15
  git_diff_exists
15
16
  commit_message.txt
16
17
  black_output.txt
@@ -4,6 +4,53 @@ This document aims to have relevant information for people contributing to and m
4
4
  It is not necessary for users of the tool to know about these processes.
5
5
  For general user information, see the [README](./README.md).
6
6
 
7
+ ## Code formatting
8
+
9
+ We use automated code formatters to ensure consistent code style / indentation.
10
+ Please format Python code with [black](https://pypi.org/project/black/), and YAML and markdown files with [Prettier](https://prettier.io/).
11
+ For simplicity's sake, we don't have a custom configuration, we use the tool's defaults.
12
+
13
+ If your editor does not do this automatically, you can run these tools from the command line:
14
+
15
+ ```bash
16
+ make format
17
+ ```
18
+
19
+ ## Installing from source:
20
+
21
+ For developers working on CFEngine CLI, it is recommended to install an editable version of the tool:
22
+
23
+ ```bash
24
+ make install
25
+ ```
26
+
27
+ Some of the tests require that you have the CLI installed (they run `cfengine` commands).
28
+
29
+ ## Running commands without installing
30
+
31
+ You can also run commands without installing, using `uv`:
32
+
33
+ ```bash
34
+ uv run cfengine format
35
+ ```
36
+
37
+ ## Running tests
38
+
39
+ Use the makefile command to run all linting and tests:
40
+
41
+ ```bash
42
+ make check
43
+ ```
44
+
45
+ Running individual test suites:
46
+
47
+ ```bash
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
52
+ ```
53
+
7
54
  ## Releasing new versions
8
55
 
9
56
  Releases are [automated using a GH Action](https://github.com/cfengine/cfengine-cli/blob/main/.github/workflows/pypi-publish.yml)
@@ -79,62 +126,11 @@ Copy the token and paste it into the GitHub Secret named `PYPI_PASSWORD`.
79
126
  `PYPI_USERNAME` should be there already, you don't have to edit it, it is simply `__token__`.
80
127
  Don't store the token anywhere else - we generate new tokens if necessary.
81
128
 
82
- ## Code formatting
83
-
84
- We use automated code formatters to ensure consistent code style / indentation.
85
- Please format Python code with [black](https://pypi.org/project/black/), and YAML and markdown files with [Prettier](https://prettier.io/).
86
- For simplicity's sake, we don't have a custom configuration, we use the tool's defaults.
87
-
88
- If your editor does not do this automatically, you can run these tools from the command line:
89
-
90
- ```bash
91
- black . && prettier . --write
92
- ```
93
-
94
- ## Running commands during development
95
-
96
- This project uses `uv`.
97
- This makes it easy to run commands without installing the project, for example:
98
-
99
- ```bash
100
- uv run cfengine format
101
- ```
102
-
103
- ## Installing from source:
104
-
105
- ```bash
106
- git fetch --all --tags
107
- pip3 install .
108
- ```
109
-
110
- ## Running tests
111
-
112
- Unit tests:
113
-
114
- ```bash
115
- py.test
116
- ```
117
-
118
- Shell tests (requires installing first):
119
-
120
- ```bash
121
- cat tests/shell/*.sh | bash
122
- ```
123
-
124
129
  ## Not implemented yet / TODOs
125
130
 
126
131
  - `cfengine run`
127
132
  - The command could automatically detect that you have CFEngine installed on a remote hub, and run it there instead (using `cf-remote`).
128
133
  - Handle when `cf-agent` is not installed, help users install.
129
134
  - Prompt / help users do what they meant (i.e. build and deploy and run).
130
- - `cfengine format`
131
- - Automatically break up and indent method calls, function calls, and nested function calls.
132
- - Smarter placement of comments based on context.
133
- - The command should be able to take a filename as an argument, and also operate using stdin and stdout.
134
- (Receive file content on stdin, file type using command line arg, output formatted file to stdout).
135
- - We can add a shortcut, `cfengine fmt`, since that matches other tools, like `deno`.
136
- - `cfengine lint`
137
- - The command should be able to take a filename as an argument, and also take file content from stdin.
138
- - It would be nice if we refactored `validate_config()` in `cfbs` so it would take a simple dictionary (JSON) instead of a special CFBSConfig object.
139
135
  - Missing commands:
140
136
  - `cfengine install` - Install CFEngine packages / binaries (Wrapping `cf-remote install`).
@@ -0,0 +1,22 @@
1
+ .PHONY: default format lint install check
2
+
3
+ default: check
4
+
5
+ format:
6
+ uv tool run black .
7
+ prettier . --write
8
+
9
+ lint:
10
+ uv tool run black --check .
11
+ uv tool run flake8 src/ --ignore=E203,W503,E722,E731 --max-complexity=100 --max-line-length=160
12
+ uv tool run pyflakes src/
13
+ uv tool run pyright src/
14
+
15
+ install:
16
+ pipx install --force --editable .
17
+
18
+ check: format lint install
19
+ uv run pytest
20
+ bash tests/run-lint-tests.sh
21
+ bash tests/run-format-tests.sh
22
+ bash tests/run-shell-tests.sh
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.12.2
3
+ Version: 0.13.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
@@ -762,8 +762,8 @@ When it finds a mistake, it points out where the problem is like this;
762
762
  ifvarclass => "cfengine";
763
763
  ^--------^
764
764
  Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
765
- FAIL: main.cf (1 errors)
766
- Failure, 1 errors in total.
765
+ FAIL: main.cf (1 error)
766
+ Failure, 1 error in total.
767
767
  ```
768
768
 
769
769
  Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
@@ -60,8 +60,8 @@ When it finds a mistake, it points out where the problem is like this;
60
60
  ifvarclass => "cfengine";
61
61
  ^--------^
62
62
  Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
63
- FAIL: main.cf (1 errors)
64
- Failure, 1 errors in total.
63
+ FAIL: main.cf (1 error)
64
+ Failure, 1 error in total.
65
65
  ```
66
66
 
67
67
  Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfengine
3
- Version: 0.12.2
3
+ Version: 0.13.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
@@ -762,8 +762,8 @@ When it finds a mistake, it points out where the problem is like this;
762
762
  ifvarclass => "cfengine";
763
763
  ^--------^
764
764
  Deprecation: Use 'if' instead of 'ifvarclass' at main.cf:5:7
765
- FAIL: main.cf (1 errors)
766
- Failure, 1 errors in total.
765
+ FAIL: main.cf (1 error)
766
+ Failure, 1 error in total.
767
767
  ```
768
768
 
769
769
  Note that since we use a different parser than `cf-agent` / `cf-promises`, they are not 100% in sync.
@@ -2,6 +2,7 @@
2
2
  .python-version
3
3
  HACKING.md
4
4
  LICENSE
5
+ Makefile
5
6
  README.md
6
7
  pyproject.toml
7
8
  uv.lock
@@ -43,13 +44,10 @@ src/cfengine_cli/masterfiles/generate_git_tags.py
43
44
  src/cfengine_cli/masterfiles/generate_release_information.py
44
45
  src/cfengine_cli/masterfiles/generate_vcf_download.py
45
46
  src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py
46
- tests/__init__.py
47
+ tests/README.md
47
48
  tests/run-format-tests.sh
49
+ tests/run-lint-tests.sh
48
50
  tests/run-shell-tests.sh
49
- tests/test_deps.py
50
- tests/test_paths.py
51
- tests/test_utils.py
52
- tests/test_version.py
53
51
  tests/format/001_hello_world.expected.cf
54
52
  tests/format/001_hello_world.input.cf
55
53
  tests/format/002_basics.expected.cf
@@ -58,6 +56,38 @@ tests/format/003_wrapping.expected.cf
58
56
  tests/format/003_wrapping.input.cf
59
57
  tests/format/004_comments.expected.cf
60
58
  tests/format/004_comments.input.cf
59
+ tests/format/005_bundle_comments.expected.cf
60
+ tests/format/005_bundle_comments.input.cf
61
+ tests/format/006_remove_empty_comments.expected.cf
62
+ tests/format/006_remove_empty_comments.input.cf
63
+ tests/format/007_class_guarded_empty_lines.expected.cf
64
+ tests/format/007_class_guarded_empty_lines.input.cf
65
+ tests/lint/001_hello_world.cf
66
+ tests/lint/002_ifvarclass.expected.txt
67
+ tests/lint/002_ifvarclass.x.cf
68
+ tests/lint/003_deprecated_promise_type.cf
69
+ tests/lint/003_deprecated_promise_type.expected.txt
70
+ tests/lint/003_deprecated_promise_type.x.cf
71
+ tests/lint/004_bundle_name_lowercase.cf
72
+ tests/lint/004_bundle_name_lowercase.expected.txt
73
+ tests/lint/004_bundle_name_lowercase.x.cf
74
+ tests/lint/005_bundle_type.cf
75
+ tests/lint/005_bundle_type.expected.txt
76
+ tests/lint/005_bundle_type.x.cf
77
+ tests/lint/006_syntax_error.cf
78
+ tests/lint/006_syntax_error.expected.txt
79
+ tests/lint/006_syntax_error.x.cf
80
+ tests/lint/007_empty_file.expected.txt
81
+ tests/lint/007_empty_file.x.cf
82
+ tests/lint/008_namespace.cf
83
+ tests/lint/008_namespace.expected.txt
84
+ tests/lint/008_namespace.x.cf
61
85
  tests/shell/001-help.sh
62
86
  tests/shell/002-version.sh
63
- tests/shell/003-format.sh
87
+ tests/shell/003-format.sh
88
+ tests/unit/__init__.py
89
+ tests/unit/test_deps.py
90
+ tests/unit/test_format.py
91
+ tests/unit/test_paths.py
92
+ tests/unit/test_utils.py
93
+ tests/unit/test_version.py
@@ -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_folder, lint_single_arg
7
+ from cfengine_cli.lint import lint_args
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
@@ -96,20 +96,16 @@ def format(names, line_length) -> int:
96
96
 
97
97
  def _lint(files, strict) -> int:
98
98
  if not files:
99
- return lint_folder(".", strict)
100
-
101
- errors = 0
102
-
103
- for file in files:
104
- errors += lint_single_arg(file, strict)
105
-
106
- return errors
99
+ return lint_args(["."], strict)
100
+ return lint_args(files, strict)
107
101
 
108
102
 
109
103
  def lint(files, strict) -> int:
110
104
  errors = _lint(files, strict)
111
105
  if errors == 0:
112
106
  print("Success, no errors found.")
107
+ elif errors == 1:
108
+ print("Failure, 1 error in total.")
113
109
  else:
114
110
  print(f"Failure, {errors} errors in total.")
115
111
  return errors
@@ -16,7 +16,8 @@ import markdown_it
16
16
  from cfbs.pretty import pretty_file
17
17
  from cfbs.utils import find
18
18
 
19
- from cfengine_cli.lint import lint_folder, lint_policy_file
19
+ from cfengine_cli.format import format_policy_file
20
+ from cfengine_cli.lint import lint_args, lint_policy_file_snippet
20
21
  from cfengine_cli.utils import UserError
21
22
 
22
23
  IGNORED_DIRS = [".git"]
@@ -127,7 +128,7 @@ def fn_check_syntax(
127
128
  first_line,
128
129
  _last_line,
129
130
  snippet_number,
130
- prefix=None,
131
+ prefix,
131
132
  ):
132
133
  snippet_abs_path = os.path.abspath(snippet_path)
133
134
 
@@ -138,8 +139,13 @@ def fn_check_syntax(
138
139
 
139
140
  match language:
140
141
  case "cf":
141
- r = lint_policy_file(
142
- snippet_abs_path, origin_path, first_line + 1, snippet_number, prefix
142
+ r = lint_policy_file_snippet(
143
+ snippet_abs_path,
144
+ origin_path,
145
+ first_line + 1,
146
+ snippet_number,
147
+ prefix,
148
+ strict=False,
143
149
  )
144
150
  if r != 0:
145
151
  raise UserError(f"Error when checking '{origin_path}'")
@@ -189,6 +195,7 @@ def fn_replace(origin_path, snippet_path, _language, first_line, last_line, inde
189
195
 
190
196
 
191
197
  def fn_autoformat(_origin_path, snippet_path, language, _first_line, _last_line):
198
+ assert language in ("cf", "json")
192
199
  match language:
193
200
  case "json":
194
201
  try:
@@ -203,6 +210,9 @@ def fn_autoformat(_origin_path, snippet_path, language, _first_line, _last_line)
203
210
  raise UserError(f"Couldn't open '{snippet_path}'")
204
211
  except json.decoder.JSONDecodeError:
205
212
  raise UserError(f"Invalid json in '{snippet_path}'")
213
+ case "cf":
214
+ # Note: Dead code - Not used for CFEngine policy yet
215
+ format_policy_file(snippet_path, 80)
206
216
 
207
217
 
208
218
  def _translate_language(x):
@@ -241,10 +251,23 @@ def _process_markdown_code_blocks(
241
251
  origin_paths = sorted(parsed_markdowns["files"].keys())
242
252
  origin_paths_len = len(origin_paths)
243
253
 
254
+ if origin_paths_len == 0:
255
+ print("No markdown files found.")
256
+ return
257
+
258
+ if syntax_check:
259
+ # We currently only print the filenames during linting, not formatting
260
+ print(
261
+ f"Processing code blocks (snippets) inside {origin_paths_len} markdown files:"
262
+ )
244
263
  for origin_paths_i, origin_path in enumerate(origin_paths):
245
264
  percentage = int(100 * (origin_paths_i + 1) / origin_paths_len)
246
- prefix = f"[{origin_paths_i + 1}/{origin_paths_len} ({percentage}%)] "
265
+ spaces = " " * (4 - len(str(percentage)))
266
+ prefix = f"[{origin_paths_i + 1}/{origin_paths_len}{spaces}({percentage}%)] "
247
267
  offset = 0
268
+ if syntax_check and not parsed_markdowns["files"][origin_path]["code-blocks"]:
269
+ print(f"{prefix}SKIP: No code blocks in '{origin_path}'")
270
+ continue
248
271
  for i, code_block in enumerate(
249
272
  parsed_markdowns["files"][origin_path]["code-blocks"]
250
273
  ):
@@ -259,33 +282,44 @@ def _process_markdown_code_blocks(
259
282
  snippet_path = f"{origin_path}.snippet-{snippet_number}.{language}"
260
283
 
261
284
  flags = code_block["flags"]
285
+ first_line = code_block["first_line"]
286
+ last_line = code_block["last_line"]
262
287
  if "noextract" in flags or "skip" in flags:
263
288
  # code block was marked to be skipped
289
+ if syntax_check:
290
+ print(
291
+ f"{prefix}SKIP: Snippet {snippet_number} at '{origin_path}:{first_line}' ({language} {' '.join(flags)})"
292
+ )
264
293
  continue
265
294
  if extract:
266
295
  fn_extract(
267
296
  origin_path,
268
297
  snippet_path,
269
298
  language,
270
- code_block["first_line"],
271
- code_block["last_line"],
299
+ first_line,
300
+ last_line,
272
301
  )
273
302
 
274
- if syntax_check and "novalidate" not in flags:
275
- try:
276
- fn_check_syntax(
277
- origin_path,
278
- snippet_path,
279
- language,
280
- code_block["first_line"],
281
- code_block["last_line"],
282
- snippet_number,
283
- prefix,
303
+ if syntax_check:
304
+ if "novalidate" in flags:
305
+ print(
306
+ f"{prefix}SKIP: Snippet {snippet_number} at '{origin_path}:{first_line}' ({language} {' '.join(flags)})"
284
307
  )
285
- except Exception as e:
286
- if cleanup:
287
- os.remove(snippet_path)
288
- raise e
308
+ else:
309
+ try:
310
+ fn_check_syntax(
311
+ origin_path,
312
+ snippet_path,
313
+ language,
314
+ first_line,
315
+ last_line,
316
+ snippet_number,
317
+ prefix,
318
+ )
319
+ except Exception as e:
320
+ if cleanup:
321
+ os.remove(snippet_path)
322
+ raise e
289
323
 
290
324
  if output_check and "noexecute" not in flags:
291
325
  fn_check_output()
@@ -295,8 +329,8 @@ def _process_markdown_code_blocks(
295
329
  origin_path,
296
330
  snippet_path,
297
331
  language,
298
- code_block["first_line"],
299
- code_block["last_line"],
332
+ first_line,
333
+ last_line,
300
334
  )
301
335
 
302
336
  if replace and "noreplace" not in flags:
@@ -304,7 +338,7 @@ def _process_markdown_code_blocks(
304
338
  origin_path,
305
339
  snippet_path,
306
340
  language,
307
- code_block["first_line"],
341
+ first_line,
308
342
  code_block["last_line"],
309
343
  code_block["indent"],
310
344
  )
@@ -409,7 +443,7 @@ def check_docs() -> int:
409
443
 
410
444
  Run by the command:
411
445
  cfengine dev lint-docs"""
412
- r = lint_folder(".", strict=False)
446
+ r = lint_args(["."], strict=False)
413
447
  if r != 0:
414
448
  return r
415
449
  _process_markdown_code_blocks(