cfengine 0.13.0__tar.gz → 0.14.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.
- cfengine-0.14.0/.github/workflows/make-check.yml +51 -0
- cfengine-0.14.0/.github/workflows/update-syntax-description.yml +69 -0
- cfengine-0.14.0/.python-version +1 -0
- cfengine-0.14.0/CLAUDE.md +51 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/HACKING.md +6 -6
- cfengine-0.14.0/Makefile +26 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/PKG-INFO +2 -2
- {cfengine-0.13.0 → cfengine-0.14.0}/pyproject.toml +4 -1
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/PKG-INFO +2 -2
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/SOURCES.txt +51 -4
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/requires.txt +1 -1
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/commands.py +43 -23
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/deptool.py +2 -2
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/dev.py +18 -26
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/docs.py +19 -23
- cfengine-0.14.0/src/cfengine_cli/format.py +901 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/lint.py +627 -104
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/main.py +8 -5
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/analyze.py +11 -17
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/download.py +1 -1
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/generate_release_information.py +53 -22
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/profile.py +1 -1
- cfengine-0.14.0/src/cfengine_cli/syntax-description.json +10343 -0
- cfengine-0.14.0/src/cfengine_cli/syntax_tree.py +42 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/002_basics.expected.cf +8 -4
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/002_basics.input.cf +7 -2
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/003_wrapping.expected.cf +33 -7
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/003_wrapping.input.cf +29 -3
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/004_comments.expected.cf +20 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/004_comments.input.cf +18 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/005_bundle_comments.expected.cf +5 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/005_bundle_comments.input.cf +5 -0
- cfengine-0.14.0/tests/format/007_class_guarded_empty_lines.expected.cf +9 -0
- cfengine-0.14.0/tests/format/008_long_string.expected.cf +6 -0
- cfengine-0.14.0/tests/format/008_long_string.input.cf +5 -0
- cfengine-0.14.0/tests/format/009_single_line.expected.cf +58 -0
- cfengine-0.14.0/tests/format/009_single_line.input.cf +76 -0
- cfengine-0.14.0/tests/format/010_stakeholder.expected.cf +119 -0
- cfengine-0.14.0/tests/format/010_stakeholder.input.cf +99 -0
- cfengine-0.14.0/tests/format/011_macros.expected.cf +192 -0
- cfengine-0.14.0/tests/format/011_macros.input.cf +182 -0
- cfengine-0.14.0/tests/format/011_promises.expected.cf +516 -0
- cfengine-0.14.0/tests/format/011_promises.input.cf +409 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/005_bundle_type.expected.txt +1 -1
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/008_namespace.cf +2 -2
- cfengine-0.14.0/tests/lint/008_namespace.expected.txt +7 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/008_namespace.x.cf +2 -2
- cfengine-0.14.0/tests/lint/009_bundle_shadows_function.cf +5 -0
- cfengine-0.14.0/tests/lint/009_bundle_shadows_function.expected.txt +6 -0
- cfengine-0.14.0/tests/lint/009_bundle_shadows_function.x.cf +5 -0
- cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.cf +24 -0
- cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.expected.txt +12 -0
- cfengine-0.14.0/tests/lint/010_unknown_function_inside_vars.x.cf +22 -0
- cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.cf +14 -0
- cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.expected.txt +12 -0
- cfengine-0.14.0/tests/lint/011_mutually_exclusive_types_vars.x.cf +17 -0
- cfengine-0.14.0/tests/lint/012_invalid_attributes.expected.txt +12 -0
- cfengine-0.14.0/tests/lint/012_invalid_attributes.x.cf +13 -0
- cfengine-0.14.0/tests/lint/013_function_call_arg_count.cf +8 -0
- cfengine-0.14.0/tests/lint/013_function_call_arg_count.expected.txt +12 -0
- cfengine-0.14.0/tests/lint/013_function_call_arg_count.x.cf +14 -0
- cfengine-0.14.0/tests/lint/014_num_args_body.expected.txt +20 -0
- cfengine-0.14.0/tests/lint/014_num_args_body.x.cf +24 -0
- cfengine-0.14.0/tests/lint/014_num_args_bundle.expected.txt +20 -0
- cfengine-0.14.0/tests/lint/014_num_args_bundle.x.cf +17 -0
- cfengine-0.14.0/tests/lint/014_num_args_bundle_body.cf +11 -0
- cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.cf +16 -0
- cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.expected.txt +12 -0
- cfengine-0.14.0/tests/lint/015_variadic_func_arg_count.x.cf +18 -0
- cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.cf +25 -0
- cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.expected.txt +14 -0
- cfengine-0.14.0/tests/lint/016_macro_multi_def_bundle.x.cf +25 -0
- cfengine-0.14.0/tests/lint/017_half_promises.cf +12 -0
- cfengine-0.14.0/tests/lint/017_half_promises.expected.txt +17 -0
- cfengine-0.14.0/tests/lint/017_half_promises.x.cf +29 -0
- cfengine-0.14.0/tests/lint/018_implies_body.cf +12 -0
- cfengine-0.14.0/tests/lint/018_implies_body.expected.txt +38 -0
- cfengine-0.14.0/tests/lint/018_implies_body.x.cf +31 -0
- cfengine-0.14.0/tests/lint/019_nested_calls.cf +22 -0
- cfengine-0.14.0/tests/lint/019_nested_calls.expected.txt +22 -0
- cfengine-0.14.0/tests/lint/019_nested_calls.x.cf +24 -0
- cfengine-0.14.0/tests/lint/020_bundle_name_expansion.cf +15 -0
- cfengine-0.14.0/tests/shell/004-format-check.sh +67 -0
- cfengine-0.14.0/tests/unit/test_format.py +514 -0
- cfengine-0.14.0/uv.lock +474 -0
- cfengine-0.13.0/.github/workflows/format.yml +0 -61
- cfengine-0.13.0/.github/workflows/lint.yml +0 -44
- cfengine-0.13.0/.github/workflows/test.yml +0 -53
- cfengine-0.13.0/.python-version +0 -1
- cfengine-0.13.0/Makefile +0 -22
- cfengine-0.13.0/src/cfengine_cli/format.py +0 -407
- cfengine-0.13.0/src/cfengine_cli/policy_language.py +0 -239
- cfengine-0.13.0/tests/format/007_class_guarded_empty_lines.expected.cf +0 -11
- cfengine-0.13.0/tests/lint/008_namespace.expected.txt +0 -7
- cfengine-0.13.0/tests/unit/test_format.py +0 -70
- cfengine-0.13.0/uv.lock +0 -474
- {cfengine-0.13.0 → cfengine-0.14.0}/.github/dependabot.yml +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/.github/workflows/pypi-publish.yml +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/.gitignore +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/LICENSE +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/README.md +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/ci/01-install.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/setup.cfg +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/README.md +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/006_remove_empty_comments.expected.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/006_remove_empty_comments.input.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/001_hello_world.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/002_ifvarclass.expected.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/002_ifvarclass.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/003_deprecated_promise_type.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/003_deprecated_promise_type.expected.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/003_deprecated_promise_type.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/004_bundle_name_lowercase.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/004_bundle_name_lowercase.expected.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/004_bundle_name_lowercase.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/005_bundle_type.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/005_bundle_type.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/006_syntax_error.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/006_syntax_error.expected.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/006_syntax_error.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/007_empty_file.expected.txt +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/lint/007_empty_file.x.cf +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/run-format-tests.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/run-lint-tests.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/run-shell-tests.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/shell/001-help.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/shell/002-version.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/shell/003-format.sh +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/unit/__init__.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/unit/test_deps.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/unit/test_paths.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/unit/test_utils.py +0 -0
- {cfengine-0.13.0 → cfengine-0.14.0}/tests/unit/test_version.py +0 -0
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
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
|
cfengine-0.14.0/Makefile
ADDED
|
@@ -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.
|
|
3
|
+
Version: 0.14.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.
|
|
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.
|
|
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.
|
|
3
|
+
Version: 0.14.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.
|
|
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
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.gitignore
|
|
2
2
|
.python-version
|
|
3
|
+
CLAUDE.md
|
|
3
4
|
HACKING.md
|
|
4
5
|
LICENSE
|
|
5
6
|
Makefile
|
|
@@ -7,10 +8,9 @@ README.md
|
|
|
7
8
|
pyproject.toml
|
|
8
9
|
uv.lock
|
|
9
10
|
.github/dependabot.yml
|
|
10
|
-
.github/workflows/
|
|
11
|
-
.github/workflows/lint.yml
|
|
11
|
+
.github/workflows/make-check.yml
|
|
12
12
|
.github/workflows/pypi-publish.yml
|
|
13
|
-
.github/workflows/
|
|
13
|
+
.github/workflows/update-syntax-description.yml
|
|
14
14
|
ci/01-install.sh
|
|
15
15
|
ci/02-safe-tests.sh
|
|
16
16
|
ci/03-unsafe-tests.sh
|
|
@@ -31,9 +31,10 @@ src/cfengine_cli/format.py
|
|
|
31
31
|
src/cfengine_cli/lint.py
|
|
32
32
|
src/cfengine_cli/main.py
|
|
33
33
|
src/cfengine_cli/paths.py
|
|
34
|
-
src/cfengine_cli/policy_language.py
|
|
35
34
|
src/cfengine_cli/profile.py
|
|
36
35
|
src/cfengine_cli/shell.py
|
|
36
|
+
src/cfengine_cli/syntax-description.json
|
|
37
|
+
src/cfengine_cli/syntax_tree.py
|
|
37
38
|
src/cfengine_cli/utils.py
|
|
38
39
|
src/cfengine_cli/version.py
|
|
39
40
|
src/cfengine_cli/masterfiles/__init__.py
|
|
@@ -62,6 +63,16 @@ tests/format/006_remove_empty_comments.expected.cf
|
|
|
62
63
|
tests/format/006_remove_empty_comments.input.cf
|
|
63
64
|
tests/format/007_class_guarded_empty_lines.expected.cf
|
|
64
65
|
tests/format/007_class_guarded_empty_lines.input.cf
|
|
66
|
+
tests/format/008_long_string.expected.cf
|
|
67
|
+
tests/format/008_long_string.input.cf
|
|
68
|
+
tests/format/009_single_line.expected.cf
|
|
69
|
+
tests/format/009_single_line.input.cf
|
|
70
|
+
tests/format/010_stakeholder.expected.cf
|
|
71
|
+
tests/format/010_stakeholder.input.cf
|
|
72
|
+
tests/format/011_macros.expected.cf
|
|
73
|
+
tests/format/011_macros.input.cf
|
|
74
|
+
tests/format/011_promises.expected.cf
|
|
75
|
+
tests/format/011_promises.input.cf
|
|
65
76
|
tests/lint/001_hello_world.cf
|
|
66
77
|
tests/lint/002_ifvarclass.expected.txt
|
|
67
78
|
tests/lint/002_ifvarclass.x.cf
|
|
@@ -82,9 +93,45 @@ tests/lint/007_empty_file.x.cf
|
|
|
82
93
|
tests/lint/008_namespace.cf
|
|
83
94
|
tests/lint/008_namespace.expected.txt
|
|
84
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
|
|
85
131
|
tests/shell/001-help.sh
|
|
86
132
|
tests/shell/002-version.sh
|
|
87
133
|
tests/shell/003-format.sh
|
|
134
|
+
tests/shell/004-format-check.sh
|
|
88
135
|
tests/unit/__init__.py
|
|
89
136
|
tests/unit/test_deps.py
|
|
90
137
|
tests/unit/test_format.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_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
|
-
|
|
55
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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.
|
|
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 "
|
|
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"]
|
|
@@ -8,6 +8,7 @@ from cfengine_cli.deptool import (
|
|
|
8
8
|
print_release_dependency_tables,
|
|
9
9
|
)
|
|
10
10
|
from cfengine_cli.docs import update_docs, check_docs
|
|
11
|
+
from cfengine_cli.syntax_tree import syntax_tree
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def generate_release_information_command(
|
|
@@ -25,53 +26,42 @@ def _continue_prompt() -> bool:
|
|
|
25
26
|
return answer in ("y", "yes")
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
def _expect_repo(repo)
|
|
29
|
+
def _expect_repo(repo):
|
|
29
30
|
cwd = os.getcwd()
|
|
30
31
|
if cwd.endswith(repo):
|
|
31
|
-
return
|
|
32
|
+
return
|
|
32
33
|
print(f"Note: This command is intended to be run in the {repo} repo")
|
|
33
34
|
print(f" https://github.com/cfengine/{repo}")
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
if not _continue_prompt():
|
|
36
|
+
raise UserError(f"Aborted (expected to be in {repo} repo)")
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
def update_dependency_tables() -> int:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return _update_dependency_tables()
|
|
42
|
-
return 1
|
|
40
|
+
_expect_repo("buildscripts")
|
|
41
|
+
return _update_dependency_tables()
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
def print_dependency_tables(args) -> int:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if answer:
|
|
49
|
-
return print_release_dependency_tables(versions)
|
|
50
|
-
return 1
|
|
45
|
+
_expect_repo("buildscripts")
|
|
46
|
+
return print_release_dependency_tables(args.versions)
|
|
51
47
|
|
|
52
48
|
|
|
53
49
|
def format_docs(files) -> int:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return update_docs(files)
|
|
57
|
-
return 1
|
|
50
|
+
_expect_repo("documentation")
|
|
51
|
+
return update_docs(files)
|
|
58
52
|
|
|
59
53
|
|
|
60
54
|
def lint_docs() -> int:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return check_docs()
|
|
64
|
-
return 1
|
|
55
|
+
_expect_repo("documentation")
|
|
56
|
+
return check_docs()
|
|
65
57
|
|
|
66
58
|
|
|
67
59
|
def generate_release_information(
|
|
68
60
|
omit_download=False, check=False, min_version=None
|
|
69
61
|
) -> int:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return 0
|
|
74
|
-
return 1
|
|
62
|
+
_expect_repo("release-information")
|
|
63
|
+
generate_release_information_command(omit_download, check, min_version)
|
|
64
|
+
return 0
|
|
75
65
|
|
|
76
66
|
|
|
77
67
|
def dispatch_dev_subcommand(subcommand, args) -> int:
|
|
@@ -83,6 +73,8 @@ def dispatch_dev_subcommand(subcommand, args) -> int:
|
|
|
83
73
|
return format_docs(args.files)
|
|
84
74
|
if subcommand == "lint-docs":
|
|
85
75
|
return lint_docs()
|
|
76
|
+
if subcommand == "syntax-tree":
|
|
77
|
+
return syntax_tree(args.file)
|
|
86
78
|
if subcommand == "generate-release-information":
|
|
87
79
|
return generate_release_information(
|
|
88
80
|
args.omit_download, args.check_against_git, args.minimum_version
|
|
@@ -212,7 +212,7 @@ def fn_autoformat(_origin_path, snippet_path, language, _first_line, _last_line)
|
|
|
212
212
|
raise UserError(f"Invalid json in '{snippet_path}'")
|
|
213
213
|
case "cf":
|
|
214
214
|
# Note: Dead code - Not used for CFEngine policy yet
|
|
215
|
-
format_policy_file(snippet_path, 80)
|
|
215
|
+
format_policy_file(snippet_path, 80, False)
|
|
216
216
|
|
|
217
217
|
|
|
218
218
|
def _translate_language(x):
|
|
@@ -346,20 +346,22 @@ def _process_markdown_code_blocks(
|
|
|
346
346
|
os.remove(snippet_path)
|
|
347
347
|
|
|
348
348
|
|
|
349
|
-
def
|
|
350
|
-
print(f"Formatting
|
|
349
|
+
def _run_formatter(tool, args, cwd, install_hint):
|
|
350
|
+
print(f"Formatting with {tool}...")
|
|
351
351
|
try:
|
|
352
352
|
subprocess.run(
|
|
353
|
-
[
|
|
353
|
+
[tool, *args],
|
|
354
354
|
capture_output=True,
|
|
355
355
|
text=True,
|
|
356
356
|
check=True,
|
|
357
|
-
cwd=
|
|
357
|
+
cwd=cwd,
|
|
358
358
|
)
|
|
359
359
|
except:
|
|
360
|
-
raise UserError(
|
|
361
|
-
|
|
362
|
-
|
|
360
|
+
raise UserError(f"Encountered an error running {tool}\nInstall: {install_hint}")
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _run_black(path):
|
|
364
|
+
_run_formatter("black", [path], ".", "pipx install black")
|
|
363
365
|
|
|
364
366
|
|
|
365
367
|
def _run_prettier(path):
|
|
@@ -378,21 +380,15 @@ def _run_prettier(path):
|
|
|
378
380
|
args.append("**.md")
|
|
379
381
|
if not args:
|
|
380
382
|
return
|
|
381
|
-
try
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
cwd=directory,
|
|
391
|
-
)
|
|
392
|
-
except:
|
|
393
|
-
raise UserError(
|
|
394
|
-
"Encountered an error running prettier\nInstall: npm install --global prettier"
|
|
395
|
-
)
|
|
383
|
+
# Warning: Beware of shell expansion if you try to run this in your terminal.
|
|
384
|
+
# Wrong: prettier --write **.markdown **.md
|
|
385
|
+
# Right: prettier --write '**.markdown' '**.md'
|
|
386
|
+
_run_formatter(
|
|
387
|
+
"prettier",
|
|
388
|
+
["--embedded-language-formatting", "off", "--write", *args],
|
|
389
|
+
directory,
|
|
390
|
+
"npm install --global prettier",
|
|
391
|
+
)
|
|
396
392
|
|
|
397
393
|
|
|
398
394
|
def _update_docs_single_arg(path):
|