cfengine 0.23.1__tar.gz → 0.23.2__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.23.1 → cfengine-0.23.2}/.coveragerc +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/lint-policy-in-other-repos.yml +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/make-check.yml +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/pypi-publish.yml +3 -3
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/renovate.yml +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/update-syntax-description.yml +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/Makefile +3 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/PKG-INFO +4 -4
- {cfengine-0.23.1 → cfengine-0.23.2}/pyproject.toml +7 -7
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/PKG-INFO +4 -4
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/SOURCES.txt +5 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/requires.txt +3 -3
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/scm_file_list.json +5 -0
- cfengine-0.23.2/src/cfengine.egg-info/scm_version.json +8 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/arg_parse.py +13 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_commands.py +28 -11
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_objects.py +4 -4
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/cfengine_utils.py +3 -3
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/commands.py +12 -0
- cfengine-0.23.2/src/cfengine_cli/container.py +52 -0
- cfengine-0.23.2/src/cfengine_cli/docker/test-agent/Dockerfile +13 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/main.py +45 -6
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/syntax-description.json +23 -11
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/004_block_type.expected.txt +1 -1
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/run-shell-tests.sh +6 -0
- cfengine-0.23.2/tests/shell/006-test-fail.sh +26 -0
- cfengine-0.23.2/tests/shell/007-test-container.sh +14 -0
- cfengine-0.23.2/tests/shell/008-cfbs-index.sh +77 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/uv.lock +130 -130
- cfengine-0.23.1/src/cfengine.egg-info/scm_version.json +0 -8
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/renovate-config.js +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/coverage.yml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/.github/workflows/stale.yml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/.gitignore +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/.python-version +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/CHEATSHEET.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/CLAUDE.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/HACKING.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/LICENSE +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/README.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/ci/01-install.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/ci/02-safe-tests.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/ci/03-unsafe-tests.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/renovate.json5 +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/setup.cfg +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/dependency_links.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/entry_points.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine.egg-info/top_level.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/__init__.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/__main__.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/cfengine_wrapper/__init__.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/changelog.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/deptool-README.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/deptool.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/dev.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/docs.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/format.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/initialize_project.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/lint.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/lint_csv.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/lint_yml.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/__init__.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/analyze.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/check_download_matches_git.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/download.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_git_tags.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_release_information.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_vcf_download.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/masterfiles/generate_vcf_git_checkout.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/paths.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/profile.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/shell.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/syntax_tree.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/up.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/utils.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/validate.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/src/cfengine_cli/version.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/README.md +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/001_hello_world.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/001_hello_world.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/002_basics.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/002_basics.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/003_wrapping.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/003_wrapping.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/004_comments.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/004_comments.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/005_bundle_comments.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/005_bundle_comments.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/006_remove_empty_comments.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/006_remove_empty_comments.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/007_class_guarded_empty_lines.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/007_class_guarded_empty_lines.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/008_long_string.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/008_long_string.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/009_single_line.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/009_single_line.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/010_stakeholder.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/010_stakeholder.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/011_macros.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/011_macros.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/011_promises.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/011_promises.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/012_sameline_comments.expected.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/format/012_sameline_comments.input.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/001_hello_world.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/002_deprecations.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/002_deprecations.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/003_name_lowercase.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/003_name_lowercase.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/003_name_lowercase.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/004_block_type.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/004_block_type.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/005_syntax_error.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/005_syntax_error.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/005_syntax_error.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/006_empty_file.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/006_empty_file.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/007_namespace.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/007_namespace.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/007_namespace.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/008_bundle_shadows_function.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/009_unknown_function_inside_vars.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/010_mutually_exclusive_types_vars.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/011_invalid_attributes.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/011_invalid_attributes.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/012_function_call_arg_count.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/013_num_args_body.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/013_num_args_body.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/013_num_args_bundle.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/013_num_args_bundle.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/013_num_args_bundle_body.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/014_variadic_func_arg_count.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/015_macro_multi_def_bundle.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/016_half_promises.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/016_half_promises.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/016_half_promises.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/017_implies_body.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/017_implies_body.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/017_implies_body.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/018_nested_calls.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/018_nested_calls.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/018_nested_calls.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/019_bundle_name_expansion.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/020_missing_braces.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/020_missing_braces.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/020_missing_semicolon.expected.txt +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/020_missing_semicolon.x.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/lint/021_reactor_strtotime_silence.cf +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/run-format-tests.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/run-lint-tests.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/run-up-validate-tests.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/shell/001-help.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/shell/002-version.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/shell/003-format.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/shell/004-format-check.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/shell/005-lint.sh +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/__init__.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_changelog.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_deps.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_format.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_lint_csv.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_lint_yml.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_paths.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_utils.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/unit/test_version.py +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/001_complex_config.yaml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/002_version.x.yaml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/003_box.x.yaml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/004_count.x.yaml +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/mocks/cloud_config.json +0 -0
- {cfengine-0.23.1 → cfengine-0.23.2}/tests/up-validate/mocks/vagrant +0 -0
|
@@ -5,7 +5,7 @@ on:
|
|
|
5
5
|
types: [published]
|
|
6
6
|
jobs:
|
|
7
7
|
release-build:
|
|
8
|
-
runs-on: ubuntu-
|
|
8
|
+
runs-on: ubuntu-26.04
|
|
9
9
|
permissions:
|
|
10
10
|
contents: read
|
|
11
11
|
steps:
|
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
name: release-dists
|
|
27
27
|
path: dist/
|
|
28
28
|
pre-release-tests:
|
|
29
|
-
runs-on: ubuntu-
|
|
29
|
+
runs-on: ubuntu-26.04
|
|
30
30
|
permissions:
|
|
31
31
|
contents: read
|
|
32
32
|
steps:
|
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
uv build
|
|
39
39
|
uv run pytest
|
|
40
40
|
pypi-publish:
|
|
41
|
-
runs-on: ubuntu-
|
|
41
|
+
runs-on: ubuntu-26.04
|
|
42
42
|
needs:
|
|
43
43
|
- release-build
|
|
44
44
|
- pre-release-tests
|
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
- name: Checkout
|
|
13
13
|
uses: actions/checkout@v7.0.1
|
|
14
14
|
- name: Self-hosted Renovate
|
|
15
|
-
uses: renovatebot/github-action@v46.
|
|
15
|
+
uses: renovatebot/github-action@v46.3.6
|
|
16
16
|
with:
|
|
17
17
|
configurationFile: .github/renovate-config.js
|
|
18
18
|
token: ${{ secrets.RENOVATE_TOKEN }}
|
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
update_syntax_desc:
|
|
16
16
|
if: contains(fromJSON('["cfengine","mendersoftware","NorthernTechHQ"]'), github.repository_owner)
|
|
17
17
|
name: Update syntax-description
|
|
18
|
-
runs-on: ubuntu-
|
|
18
|
+
runs-on: ubuntu-26.04
|
|
19
19
|
permissions:
|
|
20
20
|
contents: write
|
|
21
21
|
pull-requests: write
|
|
@@ -23,7 +23,9 @@ install:
|
|
|
23
23
|
pipx install --force --editable .
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
export COVERAGE_PROCESS_START = $(PWD)/.coveragerc
|
|
26
|
+
coverage: export COVERAGE_PROCESS_START = $(PWD)/.coveragerc
|
|
27
|
+
coverage: export COVERAGE_FILE = $(PWD)/.coverage
|
|
28
|
+
coverage: export PROJECT_ROOT = $(PWD)
|
|
27
29
|
coverage:
|
|
28
30
|
uv run coverage erase
|
|
29
31
|
uv run coverage run --parallel-mode -m pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine policy language, projects, and other CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -694,13 +694,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
694
694
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
695
695
|
Requires-Python: >=3.10
|
|
696
696
|
Description-Content-Type: text/markdown
|
|
697
|
-
Requires-Dist: cf-remote>=0.9.
|
|
698
|
-
Requires-Dist: cfbs>=5.
|
|
697
|
+
Requires-Dist: cf-remote>=0.9.6
|
|
698
|
+
Requires-Dist: cfbs>=5.8.1
|
|
699
699
|
Requires-Dist: tree-sitter-cfengine>=1.1.12
|
|
700
700
|
Requires-Dist: tree-sitter>=0.26.0
|
|
701
701
|
Requires-Dist: markdown-it-py>=4.2.0
|
|
702
702
|
Requires-Dist: pyyaml>=6.0.3
|
|
703
|
-
Requires-Dist: pydantic>=2.13.
|
|
703
|
+
Requires-Dist: pydantic>=2.13.5
|
|
704
704
|
|
|
705
705
|
# CFEngine command line interface (CLI)
|
|
706
706
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=84.0.0", "setuptools-scm>=10.
|
|
2
|
+
requires = ["setuptools>=84.0.0", "setuptools-scm>=10.3.4"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
@@ -10,13 +10,13 @@ readme = "README.md"
|
|
|
10
10
|
license = {file = "LICENSE"}
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
dependencies = [
|
|
13
|
-
"cf-remote>=0.9.
|
|
14
|
-
"cfbs>=5.
|
|
13
|
+
"cf-remote>=0.9.6",
|
|
14
|
+
"cfbs>=5.8.1",
|
|
15
15
|
"tree-sitter-cfengine>=1.1.12",
|
|
16
16
|
"tree-sitter>=0.26.0",
|
|
17
17
|
"markdown-it-py>=4.2.0",
|
|
18
18
|
"pyyaml>=6.0.3",
|
|
19
|
-
"pydantic>=2.13.
|
|
19
|
+
"pydantic>=2.13.5",
|
|
20
20
|
]
|
|
21
21
|
classifiers = [
|
|
22
22
|
"Development Status :: 3 - Alpha",
|
|
@@ -43,7 +43,7 @@ cfengine = "cfengine_cli.main:main"
|
|
|
43
43
|
license-files = [] # Workaround bug in setuptools https://github.com/astral-sh/uv/issues/9513
|
|
44
44
|
|
|
45
45
|
[tool.setuptools.package-data]
|
|
46
|
-
cfengine_cli = ["*.json"] # syntax-description.json
|
|
46
|
+
cfengine_cli = ["*.json", "docker/test-agent/Dockerfile"] # syntax-description.json, cfengine test's container
|
|
47
47
|
|
|
48
48
|
[tool.pyright]
|
|
49
49
|
include = ["src"]
|
|
@@ -54,7 +54,7 @@ venv = ".venv"
|
|
|
54
54
|
|
|
55
55
|
[dependency-groups]
|
|
56
56
|
dev = [
|
|
57
|
-
"flake8>=7.
|
|
58
|
-
"pytest>=
|
|
57
|
+
"flake8>=7.4.1",
|
|
58
|
+
"pytest>=9.1.1",
|
|
59
59
|
"coverage; python_version >= '3.10'",
|
|
60
60
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cfengine
|
|
3
|
-
Version: 0.23.
|
|
3
|
+
Version: 0.23.2
|
|
4
4
|
Summary: Human-oriented CLI for interacting with CFEngine policy language, projects, and other CFEngine tools
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -694,13 +694,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
694
694
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
695
695
|
Requires-Python: >=3.10
|
|
696
696
|
Description-Content-Type: text/markdown
|
|
697
|
-
Requires-Dist: cf-remote>=0.9.
|
|
698
|
-
Requires-Dist: cfbs>=5.
|
|
697
|
+
Requires-Dist: cf-remote>=0.9.6
|
|
698
|
+
Requires-Dist: cfbs>=5.8.1
|
|
699
699
|
Requires-Dist: tree-sitter-cfengine>=1.1.12
|
|
700
700
|
Requires-Dist: tree-sitter>=0.26.0
|
|
701
701
|
Requires-Dist: markdown-it-py>=4.2.0
|
|
702
702
|
Requires-Dist: pyyaml>=6.0.3
|
|
703
|
-
Requires-Dist: pydantic>=2.13.
|
|
703
|
+
Requires-Dist: pydantic>=2.13.5
|
|
704
704
|
|
|
705
705
|
# CFEngine command line interface (CLI)
|
|
706
706
|
|
|
@@ -33,6 +33,7 @@ src/cfengine_cli/__init__.py
|
|
|
33
33
|
src/cfengine_cli/__main__.py
|
|
34
34
|
src/cfengine_cli/changelog.py
|
|
35
35
|
src/cfengine_cli/commands.py
|
|
36
|
+
src/cfengine_cli/container.py
|
|
36
37
|
src/cfengine_cli/deptool-README.md
|
|
37
38
|
src/cfengine_cli/deptool.py
|
|
38
39
|
src/cfengine_cli/dev.py
|
|
@@ -57,6 +58,7 @@ src/cfengine_cli/cfengine_wrapper/arg_parse.py
|
|
|
57
58
|
src/cfengine_cli/cfengine_wrapper/cfengine_commands.py
|
|
58
59
|
src/cfengine_cli/cfengine_wrapper/cfengine_objects.py
|
|
59
60
|
src/cfengine_cli/cfengine_wrapper/cfengine_utils.py
|
|
61
|
+
src/cfengine_cli/docker/test-agent/Dockerfile
|
|
60
62
|
src/cfengine_cli/masterfiles/__init__.py
|
|
61
63
|
src/cfengine_cli/masterfiles/analyze.py
|
|
62
64
|
src/cfengine_cli/masterfiles/check_download_matches_git.py
|
|
@@ -158,6 +160,9 @@ tests/shell/002-version.sh
|
|
|
158
160
|
tests/shell/003-format.sh
|
|
159
161
|
tests/shell/004-format-check.sh
|
|
160
162
|
tests/shell/005-lint.sh
|
|
163
|
+
tests/shell/006-test-fail.sh
|
|
164
|
+
tests/shell/007-test-container.sh
|
|
165
|
+
tests/shell/008-cfbs-index.sh
|
|
161
166
|
tests/unit/__init__.py
|
|
162
167
|
tests/unit/test_changelog.py
|
|
163
168
|
tests/unit/test_deps.py
|
|
@@ -31,9 +31,11 @@
|
|
|
31
31
|
"src/cfengine_cli/cfengine_wrapper/cfengine_utils.py",
|
|
32
32
|
"src/cfengine_cli/changelog.py",
|
|
33
33
|
"src/cfengine_cli/commands.py",
|
|
34
|
+
"src/cfengine_cli/container.py",
|
|
34
35
|
"src/cfengine_cli/deptool-README.md",
|
|
35
36
|
"src/cfengine_cli/deptool.py",
|
|
36
37
|
"src/cfengine_cli/dev.py",
|
|
38
|
+
"src/cfengine_cli/docker/test-agent/Dockerfile",
|
|
37
39
|
"src/cfengine_cli/docs.py",
|
|
38
40
|
"src/cfengine_cli/format.py",
|
|
39
41
|
"src/cfengine_cli/initialize_project.py",
|
|
@@ -151,6 +153,9 @@
|
|
|
151
153
|
"tests/shell/003-format.sh",
|
|
152
154
|
"tests/shell/004-format-check.sh",
|
|
153
155
|
"tests/shell/005-lint.sh",
|
|
156
|
+
"tests/shell/006-test-fail.sh",
|
|
157
|
+
"tests/shell/007-test-container.sh",
|
|
158
|
+
"tests/shell/008-cfbs-index.sh",
|
|
154
159
|
"tests/unit/__init__.py",
|
|
155
160
|
"tests/unit/test_changelog.py",
|
|
156
161
|
"tests/unit/test_deps.py",
|
|
@@ -11,6 +11,15 @@ from cf_remote.args import (
|
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def _add_index_arg(parser: argparse.ArgumentParser):
|
|
15
|
+
parser.add_argument(
|
|
16
|
+
"--index",
|
|
17
|
+
help="Specify alternate index (HTTPS URL or relative path to JSON file)",
|
|
18
|
+
type=str,
|
|
19
|
+
default=None,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
14
23
|
def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
15
24
|
update_parser = subp.add_parser(
|
|
16
25
|
"update",
|
|
@@ -20,7 +29,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
20
29
|
update_parser.add_argument(
|
|
21
30
|
"to_update",
|
|
22
31
|
nargs="*",
|
|
23
|
-
help="
|
|
32
|
+
help="Module(s) to update (all modules if omitted)",
|
|
24
33
|
)
|
|
25
34
|
remove_parser = subp.add_parser(
|
|
26
35
|
"remove",
|
|
@@ -43,6 +52,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
43
52
|
nargs="+",
|
|
44
53
|
help="Module(s) for which to add",
|
|
45
54
|
)
|
|
55
|
+
_add_index_arg(add_parser)
|
|
46
56
|
search_parser = subp.add_parser(
|
|
47
57
|
"search",
|
|
48
58
|
help="Searches the build-index for specified module(s)",
|
|
@@ -53,6 +63,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
53
63
|
nargs="+",
|
|
54
64
|
help="Module(s) for which to lookup",
|
|
55
65
|
)
|
|
66
|
+
_add_index_arg(search_parser)
|
|
56
67
|
|
|
57
68
|
input_parser = subp.add_parser(
|
|
58
69
|
"input",
|
|
@@ -84,6 +95,7 @@ def parse_wrapper_args(subp: argparse._SubParsersAction):
|
|
|
84
95
|
nargs="*",
|
|
85
96
|
help="Module(s) for which you would like more info, utilizes cfbs `info` function",
|
|
86
97
|
)
|
|
98
|
+
_add_index_arg(moduleinfo_parser)
|
|
87
99
|
|
|
88
100
|
show_parser = subp.add_parser(
|
|
89
101
|
"show", help="Shows your saved host-groups or info about a specified host"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
+
from cfbs.cfbs_config import CFBSConfig
|
|
3
4
|
from cfbs.utils import is_cfbs_repo
|
|
5
|
+
from cfbs.validate import validate_index_string
|
|
4
6
|
from cfbs.commands import (
|
|
5
7
|
build_command,
|
|
6
8
|
info_command,
|
|
@@ -22,6 +24,7 @@ from cfbs.commands import (
|
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
from cfengine_cli.utils import UserError
|
|
27
|
+
from cfengine_cli.container import run_in_container
|
|
25
28
|
from cfengine_cli.cfengine_wrapper.cfengine_objects import (
|
|
26
29
|
Executable,
|
|
27
30
|
ensure_default_agent_flags,
|
|
@@ -271,10 +274,7 @@ def deploy(
|
|
|
271
274
|
|
|
272
275
|
# TODO/WOULD be nice: Deploy without run (CFE-4704: https://northerntech.atlassian.net/browse/CFE-4704)
|
|
273
276
|
if hubs:
|
|
274
|
-
|
|
275
|
-
deploy_targets = [
|
|
276
|
-
"localhost" if location == "local" else location for location in hubs
|
|
277
|
-
]
|
|
277
|
+
deploy_targets = [location for location in hubs]
|
|
278
278
|
error = deploy_command(deploy_targets, masterfiles)
|
|
279
279
|
else:
|
|
280
280
|
return deploy_command(hubs, masterfiles)
|
|
@@ -287,6 +287,14 @@ def deploy(
|
|
|
287
287
|
return error
|
|
288
288
|
|
|
289
289
|
|
|
290
|
+
def test() -> int:
|
|
291
|
+
rc = build_command()
|
|
292
|
+
if rc != 0:
|
|
293
|
+
return rc
|
|
294
|
+
|
|
295
|
+
return run_in_container("out/masterfiles")
|
|
296
|
+
|
|
297
|
+
|
|
290
298
|
def show(target: list[str] | None = None) -> int:
|
|
291
299
|
if target == [] or target is None:
|
|
292
300
|
return show_command(False)
|
|
@@ -295,7 +303,14 @@ def show(target: list[str] | None = None) -> int:
|
|
|
295
303
|
return info(target)
|
|
296
304
|
|
|
297
305
|
|
|
298
|
-
def
|
|
306
|
+
def _init_cfbs_config(index: str | None = None) -> None:
|
|
307
|
+
if index is not None:
|
|
308
|
+
validate_index_string(index)
|
|
309
|
+
CFBSConfig.get_instance(index=index)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def moduleinfo(modules: list[str], index: str | None = None) -> int:
|
|
313
|
+
_init_cfbs_config(index)
|
|
299
314
|
if modules != []:
|
|
300
315
|
return info_command(modules)
|
|
301
316
|
if not is_cfbs_repo():
|
|
@@ -312,17 +327,19 @@ def cfbs_input(modules: list[str]) -> int:
|
|
|
312
327
|
return input_command(modules, "cfengine input")
|
|
313
328
|
|
|
314
329
|
|
|
315
|
-
def cfbs_add(modules: list[str]) -> int:
|
|
316
|
-
|
|
330
|
+
def cfbs_add(modules: list[str], index: str | None = None) -> int:
|
|
331
|
+
_init_cfbs_config(index)
|
|
332
|
+
return add_command(modules, "cfengine add")
|
|
317
333
|
|
|
318
334
|
|
|
319
|
-
def cfbs_remove(modules: list[str]
|
|
320
|
-
return remove_command(modules
|
|
335
|
+
def cfbs_remove(modules: list[str]) -> int:
|
|
336
|
+
return remove_command(modules)
|
|
321
337
|
|
|
322
338
|
|
|
323
|
-
def cfbs_update(to_update) -> int:
|
|
339
|
+
def cfbs_update(to_update: list[str]) -> int:
|
|
324
340
|
return update_command(to_update)
|
|
325
341
|
|
|
326
342
|
|
|
327
|
-
def cfbs_search(modules: list[str]) -> int:
|
|
343
|
+
def cfbs_search(modules: list[str], index: str | None = None) -> int:
|
|
344
|
+
_init_cfbs_config(index)
|
|
328
345
|
return search_command(modules)
|
|
@@ -27,14 +27,14 @@ def ensure_default_agent_flags(command: str) -> str:
|
|
|
27
27
|
class Executable:
|
|
28
28
|
"""
|
|
29
29
|
A single binary (cf-agent or cf-hub) at a known location -- either
|
|
30
|
-
|
|
30
|
+
localhost or a remote host identifier ("user@ip"). Knows its own path
|
|
31
31
|
and how to run a command against itself, whether that means a local
|
|
32
32
|
subprocess or an SSH call via cf-remote.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
35
|
def __init__(self, name: str, location: str, path: str, aliases=None) -> None:
|
|
36
36
|
self.name = name # "cf-agent" / "cf-hub"
|
|
37
|
-
self.location = location # "
|
|
37
|
+
self.location = location # "localhost" or "user@ip"
|
|
38
38
|
self.path = path # absolute path to the binary at that location
|
|
39
39
|
self.aliases = (
|
|
40
40
|
aliases or []
|
|
@@ -42,7 +42,7 @@ class Executable:
|
|
|
42
42
|
|
|
43
43
|
@property
|
|
44
44
|
def is_local(self) -> bool:
|
|
45
|
-
return self.location == "
|
|
45
|
+
return self.location == "localhost"
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def label(self) -> str:
|
|
@@ -102,7 +102,7 @@ class Installation:
|
|
|
102
102
|
|
|
103
103
|
@property
|
|
104
104
|
def is_local(self) -> bool:
|
|
105
|
-
return self.location == "
|
|
105
|
+
return self.location == "localhost"
|
|
106
106
|
|
|
107
107
|
@property
|
|
108
108
|
def aliases(self) -> list:
|
|
@@ -111,16 +111,16 @@ _Id = namedtuple("_Id", "location aliases")
|
|
|
111
111
|
|
|
112
112
|
def _identities(binary_name: str) -> Iterator[_Id]:
|
|
113
113
|
"""local + every known host as (location, aliases), without connecting."""
|
|
114
|
-
yield _Id("
|
|
114
|
+
yield _Id("localhost", ["localhost", "local"])
|
|
115
115
|
for host, aliases in _known_hosts(None if binary_name == "cf-agent" else "hub"):
|
|
116
116
|
yield _Id(host, aliases)
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
def _resolve(binary_name: str, ident: _Id) -> Executable | None:
|
|
120
120
|
"""Connect (if remote) and build an Executable, or None if unavailable."""
|
|
121
|
-
if ident.location == "
|
|
121
|
+
if ident.location == "localhost":
|
|
122
122
|
path = _find_local_path(binary_name)
|
|
123
|
-
return Executable(binary_name, "
|
|
123
|
+
return Executable(binary_name, "localhost", path) if path else None
|
|
124
124
|
data = _host_info(ident.location)
|
|
125
125
|
if not data:
|
|
126
126
|
return None
|
|
@@ -12,6 +12,7 @@ from cfengine_cli.up import validate_config, up_do, resolve_templates
|
|
|
12
12
|
from cfengine_cli.initialize_project import init_policy_module, init_promise_type
|
|
13
13
|
from cf_remote.paths import cf_remote_dir
|
|
14
14
|
from cfbs.commands import init_command
|
|
15
|
+
from cfengine_cli.cfengine_wrapper.cfengine_commands import test as _cfengine_test
|
|
15
16
|
from pydantic import ValidationError
|
|
16
17
|
|
|
17
18
|
|
|
@@ -47,6 +48,17 @@ def lint(files, strict, syntax_path) -> int:
|
|
|
47
48
|
return errors
|
|
48
49
|
|
|
49
50
|
|
|
51
|
+
def test(files, strict) -> int:
|
|
52
|
+
errors = _lint(files, strict, None)
|
|
53
|
+
if errors != 0:
|
|
54
|
+
plural = "error" if errors == 1 else "errors"
|
|
55
|
+
print(f"Lint failed, {errors} {plural} in total. Skipping build/deploy/run.")
|
|
56
|
+
return errors
|
|
57
|
+
|
|
58
|
+
print("Lint passed, no errors found.")
|
|
59
|
+
return _cfengine_test()
|
|
60
|
+
|
|
61
|
+
|
|
50
62
|
def dev(subcommand, args) -> int:
|
|
51
63
|
return dispatch_dev_subcommand(subcommand, args)
|
|
52
64
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from cfengine_cli.utils import UserError
|
|
6
|
+
|
|
7
|
+
_DOCKERFILE_DIR = os.path.join(os.path.dirname(__file__), "docker", "test-agent")
|
|
8
|
+
_IMAGE_TAG = "cfengine-cli-test-agent:latest"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def require_docker() -> None:
|
|
12
|
+
if shutil.which("docker") is None:
|
|
13
|
+
raise UserError(
|
|
14
|
+
"`cfengine test` runs the built policy set inside a Docker container -- install Docker to use it."
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _ensure_image_built() -> None:
|
|
19
|
+
result = subprocess.run(
|
|
20
|
+
["docker", "build", "-q", "-t", _IMAGE_TAG, _DOCKERFILE_DIR]
|
|
21
|
+
)
|
|
22
|
+
if result.returncode != 0:
|
|
23
|
+
raise UserError("Failed to build the cfengine-test Docker image.")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def run_in_container(masterfiles_dir: str) -> int:
|
|
27
|
+
"""
|
|
28
|
+
Runs cf-agent against the given built masterfiles directory inside a container
|
|
29
|
+
"""
|
|
30
|
+
require_docker()
|
|
31
|
+
_ensure_image_built()
|
|
32
|
+
|
|
33
|
+
abs_masterfiles = os.path.abspath(masterfiles_dir)
|
|
34
|
+
result = subprocess.run(
|
|
35
|
+
[
|
|
36
|
+
"docker",
|
|
37
|
+
"run",
|
|
38
|
+
"--rm",
|
|
39
|
+
"-v",
|
|
40
|
+
f"{abs_masterfiles}:/mnt/masterfiles:ro",
|
|
41
|
+
_IMAGE_TAG,
|
|
42
|
+
"sh",
|
|
43
|
+
"-c",
|
|
44
|
+
"rm -rf /var/cfengine/inputs "
|
|
45
|
+
"&& rm -rf /var/cfengine/masterfiles "
|
|
46
|
+
"&& cp -r /mnt/masterfiles /var/cfengine/masterfiles "
|
|
47
|
+
"&& /var/cfengine/bin/cf-agent --bootstrap 127.0.0.1 "
|
|
48
|
+
"&& /var/cfengine/bin/cf-agent -KIf update.cf "
|
|
49
|
+
"&& /var/cfengine/bin/cf-agent -KI",
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
return result.returncode
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
FROM debian:13-slim
|
|
2
|
+
ENV PATH="/root/.local/bin:${PATH}"
|
|
3
|
+
|
|
4
|
+
RUN apt-get update \
|
|
5
|
+
&& apt-get install -y --no-install-recommends \
|
|
6
|
+
python3 pipx sudo procps
|
|
7
|
+
|
|
8
|
+
RUN pipx install cfengine
|
|
9
|
+
|
|
10
|
+
RUN cfengine install --clients localhost --edition community
|
|
11
|
+
|
|
12
|
+
RUN mkdir -p /var/cfengine/bin/ \
|
|
13
|
+
&& ln -sf "$(command -v python3)" /var/cfengine/bin/cfengine-selected-python
|
|
@@ -30,7 +30,14 @@ from cf_remote.validate import (
|
|
|
30
30
|
validate_deploy_args,
|
|
31
31
|
validate_destroy_args,
|
|
32
32
|
)
|
|
33
|
-
from cfbs.utils import
|
|
33
|
+
from cfbs.utils import (
|
|
34
|
+
CFBSProgrammerError,
|
|
35
|
+
CFBSExitError,
|
|
36
|
+
CFBSUserError,
|
|
37
|
+
CFBSNetworkError,
|
|
38
|
+
CFBSValidationError,
|
|
39
|
+
)
|
|
40
|
+
from cfbs.git import CFBSGitError
|
|
34
41
|
|
|
35
42
|
|
|
36
43
|
def _get_arg_parser():
|
|
@@ -88,6 +95,24 @@ def _get_arg_parser():
|
|
|
88
95
|
)
|
|
89
96
|
lnt.add_argument("files", nargs="*", help="Files to lint")
|
|
90
97
|
|
|
98
|
+
tst = subp.add_parser(
|
|
99
|
+
"test",
|
|
100
|
+
help="Lint, then build/run a cfbs project in a throwaway container as one non-interactive check",
|
|
101
|
+
description="A convenience wrapper chaining `cfengine lint`, `cfengine build`, `cfengine deploy` and `cfengine run` "
|
|
102
|
+
"to quickly test a module or policy-set end-to-end.",
|
|
103
|
+
)
|
|
104
|
+
tst.add_argument(
|
|
105
|
+
"--strict",
|
|
106
|
+
type=str,
|
|
107
|
+
default="yes",
|
|
108
|
+
help="Strict mode for linting. Default=yes, checks for undefined promise types, bundles, bodies, functions",
|
|
109
|
+
)
|
|
110
|
+
tst.add_argument(
|
|
111
|
+
"files",
|
|
112
|
+
nargs="*",
|
|
113
|
+
help="Files/Folder to lint (default is . (the entire project) )",
|
|
114
|
+
)
|
|
115
|
+
|
|
91
116
|
dev_parser = subp.add_parser(
|
|
92
117
|
"dev", help="Utilities intended for developers / maintainers of CFEngine"
|
|
93
118
|
)
|
|
@@ -230,11 +255,11 @@ def run_command_with_args(args) -> int:
|
|
|
230
255
|
if args.command == "input":
|
|
231
256
|
return cfengine_commands.cfbs_input(args.module)
|
|
232
257
|
if args.command == "add":
|
|
233
|
-
return cfengine_commands.cfbs_add(args.module)
|
|
258
|
+
return cfengine_commands.cfbs_add(args.module, args.index)
|
|
234
259
|
if args.command == "remove":
|
|
235
260
|
return cfengine_commands.cfbs_remove(args.module)
|
|
236
261
|
if args.command == "search":
|
|
237
|
-
return cfengine_commands.cfbs_search(args.module)
|
|
262
|
+
return cfengine_commands.cfbs_search(args.module, args.index)
|
|
238
263
|
if args.command == "update":
|
|
239
264
|
return cfengine_commands.cfbs_update(args.to_update)
|
|
240
265
|
if args.command == "format":
|
|
@@ -245,6 +270,11 @@ def run_command_with_args(args) -> int:
|
|
|
245
270
|
(args.strict.lower() in ("y", "ye", "yes")),
|
|
246
271
|
args.syntax_description,
|
|
247
272
|
)
|
|
273
|
+
if args.command == "test":
|
|
274
|
+
return commands.test(
|
|
275
|
+
args.files,
|
|
276
|
+
(args.strict.lower() in ("y", "ye", "yes")),
|
|
277
|
+
)
|
|
248
278
|
if args.command == "report":
|
|
249
279
|
return cfengine_commands.report(
|
|
250
280
|
target=args.hub,
|
|
@@ -340,7 +370,7 @@ def run_command_with_args(args) -> int:
|
|
|
340
370
|
if args.command == "show":
|
|
341
371
|
return cfengine_commands.show(args.hosts)
|
|
342
372
|
if args.command == "moduleinfo":
|
|
343
|
-
return cfengine_commands.moduleinfo(args.modules)
|
|
373
|
+
return cfengine_commands.moduleinfo(args.modules, args.index)
|
|
344
374
|
if args.command == "connect":
|
|
345
375
|
return cfengine_commands.connect(args.hosts)
|
|
346
376
|
raise UserError(f"Unknown command: '{args.command}'")
|
|
@@ -376,7 +406,7 @@ def validate_args(args):
|
|
|
376
406
|
if "hub" in args and args.hub:
|
|
377
407
|
log.debug(f"validate_args, hubs in args, args.hub='{args.hub}'")
|
|
378
408
|
if args.hub in ["local", "localhost"]:
|
|
379
|
-
args.hub = ["
|
|
409
|
+
args.hub = ["localhost"]
|
|
380
410
|
else:
|
|
381
411
|
args.hub = resolve_hosts(args.hub)
|
|
382
412
|
|
|
@@ -406,7 +436,16 @@ def main():
|
|
|
406
436
|
exit_code = _main()
|
|
407
437
|
assert type(exit_code) is int
|
|
408
438
|
sys.exit(exit_code)
|
|
409
|
-
except (
|
|
439
|
+
except (
|
|
440
|
+
UserError,
|
|
441
|
+
CFRUserError,
|
|
442
|
+
CFRExitError,
|
|
443
|
+
CFBSExitError,
|
|
444
|
+
CFBSUserError,
|
|
445
|
+
CFBSNetworkError,
|
|
446
|
+
CFBSValidationError,
|
|
447
|
+
CFBSGitError,
|
|
448
|
+
) as e:
|
|
410
449
|
print(str(e))
|
|
411
450
|
sys.exit(-1)
|
|
412
451
|
# Exceptions below are not expected, print extra info:
|