From 296f6648f2baf31e529d1a4cb1f3cc249006dd38 Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Fri, 22 Mar 2024 21:17:43 -0400 Subject: [PATCH 1/9] fixes saltstack/salt#66262 pillar.ls doesn't accept kwargs --- changelog/66262.fixed.md | 1 + salt/modules/pillar.py | 4 ++-- tests/pytests/unit/modules/test_pillar.py | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 changelog/66262.fixed.md diff --git a/changelog/66262.fixed.md b/changelog/66262.fixed.md new file mode 100644 index 00000000000..dea7787f21c --- /dev/null +++ b/changelog/66262.fixed.md @@ -0,0 +1 @@ +Fixed pillar.ls doesn't accept kwargs diff --git a/salt/modules/pillar.py b/salt/modules/pillar.py index 5c6ff18f2cf..a00505824c7 100644 --- a/salt/modules/pillar.py +++ b/salt/modules/pillar.py @@ -328,7 +328,7 @@ def obfuscate(*args, **kwargs): # naming chosen for consistency with grains.ls, although it breaks the short # identifier rule. -def ls(*args): +def ls(*args, **kwargs): """ .. versionadded:: 2015.8.0 @@ -342,7 +342,7 @@ def ls(*args): salt '*' pillar.ls """ - return list(items(*args)) + return list(items(*args, **kwargs)) def item(*args, **kwargs): diff --git a/tests/pytests/unit/modules/test_pillar.py b/tests/pytests/unit/modules/test_pillar.py index 6de7e33d535..3849aa59196 100644 --- a/tests/pytests/unit/modules/test_pillar.py +++ b/tests/pytests/unit/modules/test_pillar.py @@ -180,3 +180,9 @@ def test_pillar_keys(): test_key = "7:11" res = pillarmod.keys(test_key) assert res == ["12"] + + +def test_ls_pass_kwargs(pillar_value): + with patch("salt.modules.pillar.items", MagicMock(return_value=pillar_value)): + ls = sorted(pillarmod.ls(pillarenv="base")) + assert ls == ["a", "b"] From 63d83353fa67c6711083e487da087d08ecda6ab7 Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Thu, 28 Mar 2024 13:07:06 -0400 Subject: [PATCH 2/9] specify explicit kwargs for items and ls --- salt/modules/pillar.py | 51 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/salt/modules/pillar.py b/salt/modules/pillar.py index a00505824c7..e78a7644a3f 100644 --- a/salt/modules/pillar.py +++ b/salt/modules/pillar.py @@ -189,7 +189,7 @@ def get( return ret -def items(*args, **kwargs): +def items(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): """ Calls the master for a fresh pillar and generates the pillar data on the fly @@ -244,15 +244,13 @@ def items(*args, **kwargs): if args: return item(*args) - pillarenv = kwargs.get("pillarenv") if pillarenv is None: if __opts__.get("pillarenv_from_saltenv", False): - pillarenv = kwargs.get("saltenv") or __opts__["saltenv"] + pillarenv = saltenv or __opts__["saltenv"] else: pillarenv = __opts__["pillarenv"] - pillar_override = kwargs.get("pillar") - pillar_enc = kwargs.get("pillar_enc") + pillar_override = pillar if pillar_override and pillar_enc: try: @@ -328,13 +326,44 @@ def obfuscate(*args, **kwargs): # naming chosen for consistency with grains.ls, although it breaks the short # identifier rule. -def ls(*args, **kwargs): +def ls(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): """ .. versionadded:: 2015.8.0 Calls the master for a fresh pillar, generates the pillar data on the fly (same as :py:func:`items`), but only shows the available main keys. + pillar + If specified, allows for a dictionary of pillar data to be made + available to pillar and ext_pillar rendering. these pillar variables + will also override any variables of the same name in pillar or + ext_pillar. + + pillar_enc + If specified, the data passed in the ``pillar`` argument will be passed + through this renderer to decrypt it. + + .. note:: + This will decrypt on the minion side, so the specified renderer + must be set up on the minion for this to work. Alternatively, + pillar data can be decrypted master-side. For more information, see + the :ref:`Pillar Encryption ` documentation. + Pillar data that is decrypted master-side, is not decrypted until + the end of pillar compilation though, so minion-side decryption + will be necessary if the encrypted pillar data must be made + available in an decrypted state pillar/ext_pillar rendering. + + pillarenv + Pass a specific pillar environment from which to compile pillar data. + If not specified, then the minion's :conf_minion:`pillarenv` option is + not used, and if that also is not specified then all configured pillar + environments will be merged into a single pillar dictionary and + returned. + + saltenv + Included only for compatibility with + :conf_minion:`pillarenv_from_saltenv`, and is otherwise ignored. + CLI Examples: .. code-block:: bash @@ -342,7 +371,15 @@ def ls(*args, **kwargs): salt '*' pillar.ls """ - return list(items(*args, **kwargs)) + return list( + items( + *args, + pillar=pillar, + pillar_enc=pillar_enc, + pillarenv=pillarenv, + saltenv=saltenv, + ) + ) def item(*args, **kwargs): From 2f24eeb9d1247519a4c6f5acc543ecf4c0f3edfc Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Thu, 28 Mar 2024 17:59:28 -0400 Subject: [PATCH 3/9] specify explicit kwargs for pillar data and item funcs --- salt/modules/pillar.py | 79 +++++++++++++++++--- salt/utils/args.py | 2 +- tests/pytests/integration/grains/__init__.py | 0 tests/pytests/unit/modules/test_pillar.py | 5 +- 4 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 tests/pytests/integration/grains/__init__.py diff --git a/salt/modules/pillar.py b/salt/modules/pillar.py index e78a7644a3f..dbe75be88af 100644 --- a/salt/modules/pillar.py +++ b/salt/modules/pillar.py @@ -242,7 +242,7 @@ def items(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): """ # Preserve backwards compatibility if args: - return item(*args) + return item(*args, pillarenv=pillarenv, saltenv=saltenv) if pillarenv is None: if __opts__.get("pillarenv_from_saltenv", False): @@ -275,7 +275,56 @@ def items(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): # Allow pillar.data to also be used to return pillar data -data = salt.utils.functools.alias_function(items, "data") +def data(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): + """ + Calls the master for a fresh pillar, generates the pillar data on the + fly (same as :py:func:`items`) + + pillar + If specified, allows for a dictionary of pillar data to be made + available to pillar and ext_pillar rendering. these pillar variables + will also override any variables of the same name in pillar or + ext_pillar. + + pillar_enc + If specified, the data passed in the ``pillar`` argument will be passed + through this renderer to decrypt it. + + .. note:: + This will decrypt on the minion side, so the specified renderer + must be set up on the minion for this to work. Alternatively, + pillar data can be decrypted master-side. For more information, see + the :ref:`Pillar Encryption ` documentation. + Pillar data that is decrypted master-side, is not decrypted until + the end of pillar compilation though, so minion-side decryption + will be necessary if the encrypted pillar data must be made + available in an decrypted state pillar/ext_pillar rendering. + + pillarenv + Pass a specific pillar environment from which to compile pillar data. + If not specified, then the minion's :conf_minion:`pillarenv` option is + not used, and if that also is not specified then all configured pillar + environments will be merged into a single pillar dictionary and + returned. + + saltenv + Included only for compatibility with + :conf_minion:`pillarenv_from_saltenv`, and is otherwise ignored. + + CLI Examples: + + .. code-block:: bash + + salt '*' pillar.data + """ + + return items( + *args, + pillar=pillar, + pillar_enc=pillar_enc, + pillarenv=pillarenv, + saltenv=saltenv, + ) def _obfuscate_inner(var): @@ -294,7 +343,7 @@ def _obfuscate_inner(var): return f"<{var.__class__.__name__}>" -def obfuscate(*args, **kwargs): +def obfuscate(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): """ .. versionadded:: 2015.8.0 @@ -321,7 +370,15 @@ def obfuscate(*args, **kwargs): salt '*' pillar.obfuscate """ - return _obfuscate_inner(items(*args, **kwargs)) + return _obfuscate_inner( + items( + *args, + pillar=pillar, + pillar_enc=pillar_enc, + pillarenv=pillarenv, + saltenv=saltenv, + ) + ) # naming chosen for consistency with grains.ls, although it breaks the short @@ -382,7 +439,7 @@ def ls(*args, pillar=None, pillar_enc=None, pillarenv=None, saltenv=None): ) -def item(*args, **kwargs): +def item(*args, default=None, delimiter=None, pillarenv=None, saltenv=None): """ .. versionadded:: 0.16.2 @@ -436,10 +493,12 @@ def item(*args, **kwargs): salt '*' pillar.item foo bar baz """ ret = {} - default = kwargs.get("default", "") - delimiter = kwargs.get("delimiter", DEFAULT_TARGET_DELIM) - pillarenv = kwargs.get("pillarenv", None) - saltenv = kwargs.get("saltenv", None) + + if default is None: + default = "" + + if delimiter is None: + delimiter = DEFAULT_TARGET_DELIM pillar_dict = ( __pillar__ @@ -450,7 +509,7 @@ def item(*args, **kwargs): try: for arg in args: ret[arg] = salt.utils.data.traverse_dict_and_list( - pillar_dict, arg, default, delimiter + data=pillar_dict, key=arg, default=default, delimiter=delimiter ) except KeyError: pass diff --git a/salt/utils/args.py b/salt/utils/args.py index 551099ce7b4..8a9b38eb1b0 100644 --- a/salt/utils/args.py +++ b/salt/utils/args.py @@ -252,7 +252,7 @@ def get_function_argspec(func, is_class_method=None): defaults = [] varargs = keywords = None for param in sig.parameters.values(): - if param.kind == param.POSITIONAL_OR_KEYWORD: + if param.kind in [param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY]: args.append(param.name) if param.default is not inspect._empty: defaults.append(param.default) diff --git a/tests/pytests/integration/grains/__init__.py b/tests/pytests/integration/grains/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/pytests/unit/modules/test_pillar.py b/tests/pytests/unit/modules/test_pillar.py index 3849aa59196..6acca56993c 100644 --- a/tests/pytests/unit/modules/test_pillar.py +++ b/tests/pytests/unit/modules/test_pillar.py @@ -43,7 +43,10 @@ def test_obfuscate_with_kwargs(pillar_value): ) as pillar_items_mock: ret = pillarmod.obfuscate(saltenv="saltenv") # ensure the kwargs are passed along to pillar.items - assert call(saltenv="saltenv") in pillar_items_mock.mock_calls + assert ( + call(pillar=None, pillar_enc=None, pillarenv=None, saltenv="saltenv") + in pillar_items_mock.mock_calls + ) assert ret == dict(a="", b="") From 3c97e7f0d3fa4dda30d697d7bc8d8fb27b37a1c4 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 2 Apr 2024 15:28:47 +0100 Subject: [PATCH 4/9] Do not run nightly or scheduled builds on private repos --- .github/workflows/nightly.yml | 5 +++++ .github/workflows/scheduled.yml | 5 +++++ .../templates/workflow-requirements-check.yml.jinja | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3a7db8b4c2b..1fbbd65e6d0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -57,6 +57,11 @@ jobs: echo "${MSG}" echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" echo "requirements-met=false" >> "${GITHUB_OUTPUT}" + elif [ "${{ github.event.repository.private }}" = "true" ]; then + MSG="Not running workflow because ${{ github.repository }} is a private repository" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=false" >> "${GITHUB_OUTPUT}" else MSG="Running workflow because ${{ github.repository }} is not a fork" echo "${MSG}" diff --git a/.github/workflows/scheduled.yml b/.github/workflows/scheduled.yml index 0bd6ef698a2..724b529fb74 100644 --- a/.github/workflows/scheduled.yml +++ b/.github/workflows/scheduled.yml @@ -47,6 +47,11 @@ jobs: echo "${MSG}" echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" echo "requirements-met=false" >> "${GITHUB_OUTPUT}" + elif [ "${{ github.event.repository.private }}" = "true" ]; then + MSG="Not running workflow because ${{ github.repository }} is a private repository" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=false" >> "${GITHUB_OUTPUT}" else MSG="Running workflow because ${{ github.repository }} is not a fork" echo "${MSG}" diff --git a/.github/workflows/templates/workflow-requirements-check.yml.jinja b/.github/workflows/templates/workflow-requirements-check.yml.jinja index 419ee3f6f52..67e04eef3e7 100644 --- a/.github/workflows/templates/workflow-requirements-check.yml.jinja +++ b/.github/workflows/templates/workflow-requirements-check.yml.jinja @@ -21,6 +21,11 @@ echo "${MSG}" echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" echo "requirements-met=false" >> "${GITHUB_OUTPUT}" + elif [ "${{ github.event.repository.private }}" = "true" ]; then + MSG="Not running workflow because ${{ github.repository }} is a private repository" + echo "${MSG}" + echo "${MSG}" >> "${GITHUB_STEP_SUMMARY}" + echo "requirements-met=false" >> "${GITHUB_OUTPUT}" else MSG="Running workflow because ${{ github.repository }} is not a fork" echo "${MSG}" From ecb537efef4932a4124e1fda0970f21e47277e72 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Tue, 2 Apr 2024 15:52:09 +0100 Subject: [PATCH 5/9] Define additional `needs` for a few jobs --- .github/workflows/nightly.yml | 3 +++ .github/workflows/staging.yml | 3 +++ .github/workflows/templates/build-repos.yml.jinja | 1 + .github/workflows/templates/nightly.yml.jinja | 2 ++ 4 files changed, 9 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 1fbbd65e6d0..b4be3f81e05 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -2039,6 +2039,7 @@ jobs: needs: - prepare-workflow - build-source-tarball + - build-pkgs-src strategy: fail-fast: false matrix: @@ -2782,6 +2783,7 @@ jobs: environment: nightly needs: - prepare-workflow + - build-docs - build-src-repo - build-deb-repo - build-rpm-repo @@ -2822,6 +2824,7 @@ jobs: - ubuntu-2204-arm64 steps: + - uses: actions/checkout@v4 - name: Get Salt Project GitHub Actions Bot Environment diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index 72096c06465..c29e4877dac 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -1876,6 +1876,7 @@ jobs: needs: - prepare-workflow - build-source-tarball + - build-pkgs-src strategy: fail-fast: false matrix: @@ -2621,6 +2622,7 @@ jobs: environment: staging needs: - prepare-workflow + - build-docs - build-src-repo - build-deb-repo - build-rpm-repo @@ -2629,6 +2631,7 @@ jobs: - build-onedir-repo steps: + - uses: actions/checkout@v4 - name: Get Salt Project GitHub Actions Bot Environment diff --git a/.github/workflows/templates/build-repos.yml.jinja b/.github/workflows/templates/build-repos.yml.jinja index 6b8177498df..f1d58b38121 100644 --- a/.github/workflows/templates/build-repos.yml.jinja +++ b/.github/workflows/templates/build-repos.yml.jinja @@ -25,6 +25,7 @@ - build-salt-onedir <%- elif type == 'src' %> - build-source-tarball + - build-pkgs-src <%- endif %> <%- include "build-{}-repo.yml.jinja".format(type) %> diff --git a/.github/workflows/templates/nightly.yml.jinja b/.github/workflows/templates/nightly.yml.jinja index 097ccc7d2bb..313e7297150 100644 --- a/.github/workflows/templates/nightly.yml.jinja +++ b/.github/workflows/templates/nightly.yml.jinja @@ -146,6 +146,7 @@ concurrency: environment: <{ gh_environment }> needs: - prepare-workflow + - build-docs <%- for need in build_repo_needs.iter(consume=True) %> - <{ need }> <%- endfor %> @@ -156,6 +157,7 @@ concurrency: <%- endif %> steps: + - uses: actions/checkout@v4 - name: Get Salt Project GitHub Actions Bot Environment From 1a8ea6b34353b8456f0b0ef702ad5cb543bf8f35 Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 3 Apr 2024 09:02:49 +0100 Subject: [PATCH 6/9] Revert "Make fixtures clean up even if the test fails" This reverts commit 176fe04e8d0fd00fb57b92c5f6838a6387917a71. --- tests/pytests/functional/modules/test_chocolatey.py | 8 +++----- .../functional/states/chocolatey/test_bootstrap.py | 12 ++++-------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/pytests/functional/modules/test_chocolatey.py b/tests/pytests/functional/modules/test_chocolatey.py index 904026dd93e..d11cdf6cbed 100644 --- a/tests/pytests/functional/modules/test_chocolatey.py +++ b/tests/pytests/functional/modules/test_chocolatey.py @@ -3,7 +3,7 @@ import pytest from salt.exceptions import CommandExecutionError pytestmark = [ - pytest.mark.destructive_test, + pytest.mark.destructive, pytest.mark.skip_unless_on_windows, pytest.mark.slow_test, pytest.mark.windows_whitelisted, @@ -23,10 +23,8 @@ def clean(chocolatey): except CommandExecutionError: chocolatey_version = None assert chocolatey_version is None - try: - yield - finally: - chocolatey.unbootstrap() + yield + chocolatey.unbootstrap() def test_bootstrap(chocolatey, clean): diff --git a/tests/pytests/functional/states/chocolatey/test_bootstrap.py b/tests/pytests/functional/states/chocolatey/test_bootstrap.py index 6b6bc62f558..0d37d67c665 100644 --- a/tests/pytests/functional/states/chocolatey/test_bootstrap.py +++ b/tests/pytests/functional/states/chocolatey/test_bootstrap.py @@ -28,10 +28,8 @@ def clean(chocolatey_mod): except CommandExecutionError: chocolatey_version = None assert chocolatey_version is None - try: - yield - finally: - chocolatey_mod.unbootstrap() + yield + chocolatey_mod.unbootstrap() @pytest.fixture() @@ -42,10 +40,8 @@ def installed(chocolatey_mod): except CommandExecutionError: chocolatey_version = None assert chocolatey_version is not None - try: - yield - finally: - chocolatey_mod.unbootstrap() + yield + chocolatey_mod.unbootstrap() def test_bootstrapped(chocolatey, chocolatey_mod, clean): From 944d3cd744bd32e45fecedabef7d1520736f01da Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 3 Apr 2024 09:02:49 +0100 Subject: [PATCH 7/9] Revert "Fix some lint" This reverts commit eb785bdf303d01323c6324b4754c8da0f72fd3e5. --- .../chocolatey/{test_post_20.py => test_post_2.0.py} | 0 .../states/chocolatey/{test_pre_20.py => test_pre_2.0.py} | 0 tests/pytests/unit/modules/test_chocolatey.py | 8 +++++--- 3 files changed, 5 insertions(+), 3 deletions(-) rename tests/pytests/functional/states/chocolatey/{test_post_20.py => test_post_2.0.py} (100%) rename tests/pytests/functional/states/chocolatey/{test_pre_20.py => test_pre_2.0.py} (100%) diff --git a/tests/pytests/functional/states/chocolatey/test_post_20.py b/tests/pytests/functional/states/chocolatey/test_post_2.0.py similarity index 100% rename from tests/pytests/functional/states/chocolatey/test_post_20.py rename to tests/pytests/functional/states/chocolatey/test_post_2.0.py diff --git a/tests/pytests/functional/states/chocolatey/test_pre_20.py b/tests/pytests/functional/states/chocolatey/test_pre_2.0.py similarity index 100% rename from tests/pytests/functional/states/chocolatey/test_pre_20.py rename to tests/pytests/functional/states/chocolatey/test_pre_2.0.py diff --git a/tests/pytests/unit/modules/test_chocolatey.py b/tests/pytests/unit/modules/test_chocolatey.py index a98b5ca1bca..0f6207e2382 100644 --- a/tests/pytests/unit/modules/test_chocolatey.py +++ b/tests/pytests/unit/modules/test_chocolatey.py @@ -345,9 +345,11 @@ def test_chocolatey_version_refresh(): context = {"chocolatey._version": "0.9.9"} mock_find = MagicMock(return_value="some_path") mock_run = MagicMock(return_value="2.2.0") - with patch.dict(chocolatey.__context__, context), patch.object( - chocolatey, "_find_chocolatey", mock_find - ), patch.dict(chocolatey.__salt__, {"cmd.run": mock_run}): + with ( + patch.dict(chocolatey.__context__, context), + patch.object(chocolatey, "_find_chocolatey", mock_find), + patch.dict(chocolatey.__salt__, {"cmd.run": mock_run}), + ): result = chocolatey.chocolatey_version(refresh=True) expected = "2.2.0" assert result == expected From 5c0a890078dfb2ce0bdb121fe50d1b6b4fe5789a Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 3 Apr 2024 09:02:49 +0100 Subject: [PATCH 8/9] Revert "Add the ability to bootstrap a specific version of chocolatey" This reverts commit 0f9f619e9074f72237f377a5ecaf74d807251ec4. --- changelog/64722.added.md | 3 - salt/modules/chocolatey.py | 44 +---- salt/states/chocolatey.py | 181 +----------------- .../functional/modules/test_chocolatey.py | 45 ----- .../states/chocolatey/test_bootstrap.py | 100 ---------- ...st_pre_2.0.py => test_chocolatey_1_2_1.py} | 2 +- ..._post_2.0.py => test_chocolatey_latest.py} | 2 +- tests/pytests/unit/modules/test_chocolatey.py | 32 +--- 8 files changed, 13 insertions(+), 396 deletions(-) delete mode 100644 changelog/64722.added.md delete mode 100644 tests/pytests/functional/modules/test_chocolatey.py delete mode 100644 tests/pytests/functional/states/chocolatey/test_bootstrap.py rename tests/pytests/functional/states/{chocolatey/test_pre_2.0.py => test_chocolatey_1_2_1.py} (98%) rename tests/pytests/functional/states/{chocolatey/test_post_2.0.py => test_chocolatey_latest.py} (98%) diff --git a/changelog/64722.added.md b/changelog/64722.added.md deleted file mode 100644 index 6a05d2f59d6..00000000000 --- a/changelog/64722.added.md +++ /dev/null @@ -1,3 +0,0 @@ -Added the ability to pass a version of chocolatey to install to the -chocolatey.bootstrap function. Also added states to bootstrap and -unbootstrap chocolatey. diff --git a/salt/modules/chocolatey.py b/salt/modules/chocolatey.py index d618a175572..ade057da95c 100644 --- a/salt/modules/chocolatey.py +++ b/salt/modules/chocolatey.py @@ -14,7 +14,6 @@ from requests.structures import CaseInsensitiveDict import salt.utils.data import salt.utils.platform -import salt.utils.win_dotnet from salt.exceptions import ( CommandExecutionError, CommandNotFoundError, @@ -127,26 +126,16 @@ def _find_chocolatey(): raise CommandExecutionError(err) -def chocolatey_version(refresh=False): +def chocolatey_version(): """ Returns the version of Chocolatey installed on the minion. - Args: - - refresh (bool): - Refresh the cached version of chocolatey - - .. versionadded:: 3008.0 - CLI Example: .. code-block:: bash salt '*' chocolatey.chocolatey_version """ - if refresh: - __context__.pop("chocolatey._version", False) - if "chocolatey._version" in __context__: return __context__["chocolatey._version"] @@ -158,7 +147,7 @@ def chocolatey_version(refresh=False): return __context__["chocolatey._version"] -def bootstrap(force=False, source=None, version=None): +def bootstrap(force=False, source=None): """ Download and install the latest version of the Chocolatey package manager via the official bootstrap. @@ -177,11 +166,6 @@ def bootstrap(force=False, source=None, version=None): and .NET requirements must already be met on the target. This shouldn't be a problem on Windows versions 2012/8 and later - .. note:: - If you're installing chocolatey version 2.0+ the system requires .NET - 4.8. Installing this requires a reboot, therefore this module will not - automatically install .NET 4.8. - Args: force (bool): @@ -198,12 +182,6 @@ def bootstrap(force=False, source=None, version=None): .. versionadded:: 3001 - version (str): - The version of chocolatey to install. The latest version is - installed if this value is ``None``. Default is ``None`` - - .. versionadded:: 3008.0 - Returns: str: The stdout of the Chocolatey installation script @@ -220,9 +198,6 @@ def bootstrap(force=False, source=None, version=None): # To bootstrap Chocolatey from a file on C:\\Temp salt '*' chocolatey.bootstrap source=C:\\Temp\\chocolatey.nupkg - - # To bootstrap Chocolatey version 1.4.0 - salt '*' chocolatey.bootstrap version=1.4.0 """ # Check if Chocolatey is already present in the path try: @@ -297,7 +272,7 @@ def bootstrap(force=False, source=None, version=None): # Check that .NET v4.0+ is installed # Windows 7 / Windows Server 2008 R2 and below do not come with at least # .NET v4.0 installed - if not salt.utils.win_dotnet.version_at_least(version="4"): + if not __utils__["dotnet.version_at_least"](version="4"): # It took until .NET v4.0 for Microsoft got the hang of making # installers, this should work under any version of Windows url = "http://download.microsoft.com/download/1/B/E/1BE39E79-7E39-46A3-96FF-047F95396215/dotNetFx40_Full_setup.exe" @@ -361,21 +336,10 @@ def bootstrap(force=False, source=None, version=None): f"Failed to find Chocolatey installation script: {script}" ) - # You tell the chocolatey install script which version to install by setting - # an environment variable - if version: - env = {"chocolateyVersion": version} - else: - env = None - # Run the Chocolatey bootstrap log.debug("Installing Chocolatey: %s", script) result = __salt__["cmd.script"]( - source=script, - cwd=os.path.dirname(script), - shell="powershell", - python_shell=True, - env=env, + script, cwd=os.path.dirname(script), shell="powershell", python_shell=True ) if result["retcode"] != 0: err = "Bootstrapping Chocolatey failed: {}".format(result["stderr"]) diff --git a/salt/states/chocolatey.py b/salt/states/chocolatey.py index 9c8f1951cad..5e49113607e 100644 --- a/salt/states/chocolatey.py +++ b/salt/states/chocolatey.py @@ -11,7 +11,7 @@ Manage Windows Packages using Chocolatey import salt.utils.data import salt.utils.versions -from salt.exceptions import CommandExecutionError, SaltInvocationError +from salt.exceptions import SaltInvocationError def __virtual__(): @@ -513,182 +513,3 @@ def source_present( ret["changes"] = salt.utils.data.compare_dicts(pre_install, post_install) return ret - - -def bootstrapped(name, force=False, source=None, version=None): - """ - .. versionadded:: 3008.0 - - Ensure chocolatey is installed on the system. - - You can't upgrade an existing installation with this state. You must use - chocolatey to upgrade chocolatey. - - For example: - - .. code-block:: bash - - choco upgrade chocolatey --version 2.2.0 - - Args: - - name (str): - The name of the state that installs chocolatey. Required for all - states. This is ignored. - - force (bool): - Run the bootstrap process even if Chocolatey is found in the path. - - .. note:: - If chocolatey is already installed this will just re-run the - install script over the existing version. The ``version`` - parameter is ignored. - - source (str): - The location of the ``.nupkg`` file or ``.ps1`` file to run from an - alternate location. This can be one of the following types of URLs: - - - salt:// - - http(s):// - - ftp:// - - file:// - A local file on the system - - version (str): - The version of chocolatey to install. The latest version is - installed if this value is ``None``. Default is ``None`` - - Example: - - .. code-block:: yaml - - # Bootstrap the latest version of chocolatey - bootstrap_chocolatey: - chocolatey.bootstrapped - - # Bootstrap the latest version of chocolatey - # If chocolatey is already present, re-run the install script - bootstrap_chocolatey: - chocolatey.bootstrapped: - - force: True - - # Bootstrap Chocolatey version 1.4.0 - bootstrap_chocolatey: - chocolatey.bootstrapped: - - version: 1.4.0 - - # Bootstrap Chocolatey from a local file - bootstrap_chocolatey: - chocolatey.bootstrapped: - - source: C:\\Temp\\chocolatey.nupkg - - # Bootstrap Chocolatey from a file on the salt master - bootstrap_chocolatey: - chocolatey.bootstrapped: - - source: salt://Temp/chocolatey.nupkg - """ - ret = {"name": name, "result": True, "changes": {}, "comment": ""} - - try: - old = __salt__["chocolatey.chocolatey_version"]() - except CommandExecutionError: - old = None - - # Try to predict what will happen - if old: - if force: - ret["comment"] = ( - f"Chocolatey {old} will be reinstalled\n" - 'Use "choco upgrade chocolatey --version 2.1.0" to change the version' - ) - else: - # You can't upgrade chocolatey using the install script, you have to use - # chocolatey itself - ret["comment"] = ( - f"Chocolatey {old} is already installed.\n" - 'Use "choco upgrade chocolatey --version 2.1.0" to change the version' - ) - return ret - - else: - if version is None: - ret["comment"] = "The latest version of Chocolatey will be installed" - else: - ret["comment"] = f"Chocolatey {version} will be installed" - - if __opts__["test"]: - ret["result"] = None - return ret - - __salt__["chocolatey.bootstrap"](force=force, source=source, version=version) - - try: - new = __salt__["chocolatey.chocolatey_version"](refresh=True) - except CommandExecutionError: - new = None - - if new is None: - ret["comment"] = f"Failed to install chocolatey {new}" - ret["result"] = False - else: - if salt.utils.versions.version_cmp(old, new) == 0: - ret["comment"] = f"Re-installed chocolatey {new}" - else: - ret["comment"] = f"Installed chocolatey {new}" - ret["changes"] = {"old": old, "new": new} - - return ret - - -def unbootstrapped(name): - """ - .. versionadded:: 3008.0 - - Ensure chocolatey is removed from the system. - - Args: - - name (str): - The name of the state that uninstalls chocolatey. Required for all - states. This is ignored. - - Example: - - .. code-block:: yaml - - # Uninstall chocolatey - uninstall_chocolatey: - chocolatey.unbootstrapped - - """ - ret = {"name": name, "result": True, "changes": {}, "comment": ""} - - try: - old = __salt__["chocolatey.chocolatey_version"]() - except CommandExecutionError: - old = None - - if old is None: - ret["comment"] = "Chocolatey not found on this system" - return ret - - ret["comment"] = f"Chocolatey {old} will be removed" - - if __opts__["test"]: - ret["result"] = None - return ret - - __salt__["chocolatey.unbootstrap"]() - - try: - new = __salt__["chocolatey.chocolatey_version"](refresh=True) - except CommandExecutionError: - new = None - - if new is None: - ret["comment"] = f"Uninstalled chocolatey {old}" - ret["changes"] = {"new": new, "old": old} - else: - ret["comment"] = f"Failed to uninstall chocolatey {old}\nFound version {new}" - ret["result"] = False - - return ret diff --git a/tests/pytests/functional/modules/test_chocolatey.py b/tests/pytests/functional/modules/test_chocolatey.py deleted file mode 100644 index d11cdf6cbed..00000000000 --- a/tests/pytests/functional/modules/test_chocolatey.py +++ /dev/null @@ -1,45 +0,0 @@ -import pytest - -from salt.exceptions import CommandExecutionError - -pytestmark = [ - pytest.mark.destructive, - pytest.mark.skip_unless_on_windows, - pytest.mark.slow_test, - pytest.mark.windows_whitelisted, -] - - -@pytest.fixture(scope="module") -def chocolatey(modules): - return modules.chocolatey - - -@pytest.fixture() -def clean(chocolatey): - chocolatey.unbootstrap() - try: - chocolatey_version = chocolatey.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is None - yield - chocolatey.unbootstrap() - - -def test_bootstrap(chocolatey, clean): - chocolatey.bootstrap() - try: - chocolatey_version = chocolatey.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is not None - - -def test_bootstrap_version(chocolatey, clean): - chocolatey.bootstrap(version="1.4.0") - try: - chocolatey_version = chocolatey.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version == "1.4.0" diff --git a/tests/pytests/functional/states/chocolatey/test_bootstrap.py b/tests/pytests/functional/states/chocolatey/test_bootstrap.py deleted file mode 100644 index 0d37d67c665..00000000000 --- a/tests/pytests/functional/states/chocolatey/test_bootstrap.py +++ /dev/null @@ -1,100 +0,0 @@ -import pytest - -from salt.exceptions import CommandExecutionError - -pytestmark = [ - pytest.mark.destructive_test, - pytest.mark.skip_unless_on_windows, - pytest.mark.slow_test, - pytest.mark.windows_whitelisted, -] - - -@pytest.fixture(scope="module") -def chocolatey(states): - yield states.chocolatey - - -@pytest.fixture(scope="module") -def chocolatey_mod(modules): - yield modules.chocolatey - - -@pytest.fixture() -def clean(chocolatey_mod): - chocolatey_mod.unbootstrap() - try: - chocolatey_version = chocolatey_mod.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is None - yield - chocolatey_mod.unbootstrap() - - -@pytest.fixture() -def installed(chocolatey_mod): - chocolatey_mod.bootstrap(force=True) - try: - chocolatey_version = chocolatey_mod.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is not None - yield - chocolatey_mod.unbootstrap() - - -def test_bootstrapped(chocolatey, chocolatey_mod, clean): - ret = chocolatey.bootstrapped(name="junk name") - assert "Installed chocolatey" in ret.comment - assert ret.result is True - try: - chocolatey_version = chocolatey_mod.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is not None - - -def test_bootstrapped_test_true(chocolatey, clean): - ret = chocolatey.bootstrapped(name="junk name", test=True) - assert ret.result is None - assert ret.comment == "The latest version of Chocolatey will be installed" - - -def test_bootstrapped_version(chocolatey, chocolatey_mod, clean): - ret = chocolatey.bootstrapped(name="junk_name", version="1.4.0") - assert ret.comment == "Installed chocolatey 1.4.0" - assert ret.result is True - try: - chocolatey_version = chocolatey_mod.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version == "1.4.0" - - -def test_bootstrapped_version_test_true(chocolatey, chocolatey_mod, clean): - ret = chocolatey.bootstrapped(name="junk_name", version="1.4.0", test=True) - assert ret.comment == "Chocolatey 1.4.0 will be installed" - - -def test_unbootstrapped_installed(chocolatey, chocolatey_mod, installed): - ret = chocolatey.unbootstrapped(name="junk_name") - assert "Uninstalled chocolatey" in ret.comment - assert ret.result is True - try: - chocolatey_version = chocolatey_mod.chocolatey_version(refresh=True) - except CommandExecutionError: - chocolatey_version = None - assert chocolatey_version is None - - -def test_unbootstrapped_installed_test_true(chocolatey, chocolatey_mod, installed): - ret = chocolatey.unbootstrapped(name="junk_name", test=True) - assert "will be removed" in ret.comment - assert ret.result is None - - -def test_unbootstrapped_clean(chocolatey, chocolatey_mod, clean): - ret = chocolatey.unbootstrapped(name="junk_name") - assert ret.comment == "Chocolatey not found on this system" - assert ret.result is True diff --git a/tests/pytests/functional/states/chocolatey/test_pre_2.0.py b/tests/pytests/functional/states/test_chocolatey_1_2_1.py similarity index 98% rename from tests/pytests/functional/states/chocolatey/test_pre_2.0.py rename to tests/pytests/functional/states/test_chocolatey_1_2_1.py index 0d00d313854..0e9972df17e 100644 --- a/tests/pytests/functional/states/chocolatey/test_pre_2.0.py +++ b/tests/pytests/functional/states/test_chocolatey_1_2_1.py @@ -1,5 +1,5 @@ """ -Functional tests for chocolatey state with Chocolatey < 2.0 +Functional tests for chocolatey state """ import os diff --git a/tests/pytests/functional/states/chocolatey/test_post_2.0.py b/tests/pytests/functional/states/test_chocolatey_latest.py similarity index 98% rename from tests/pytests/functional/states/chocolatey/test_post_2.0.py rename to tests/pytests/functional/states/test_chocolatey_latest.py index 5e62c86d1db..41ba0df5b38 100644 --- a/tests/pytests/functional/states/chocolatey/test_post_2.0.py +++ b/tests/pytests/functional/states/test_chocolatey_latest.py @@ -1,5 +1,5 @@ """ -Functional tests for chocolatey state with Chocolatey 2.0+ +Functional tests for chocolatey state """ import os diff --git a/tests/pytests/unit/modules/test_chocolatey.py b/tests/pytests/unit/modules/test_chocolatey.py index 0f6207e2382..8dd630793f1 100644 --- a/tests/pytests/unit/modules/test_chocolatey.py +++ b/tests/pytests/unit/modules/test_chocolatey.py @@ -7,10 +7,14 @@ import os import pytest import salt.modules.chocolatey as chocolatey +import salt.utils +import salt.utils.platform from tests.support.mock import MagicMock, patch pytestmark = [ - pytest.mark.skip_unless_on_windows, + pytest.mark.skipif( + not salt.utils.platform.is_windows(), reason="Not a Windows system" + ) ] @@ -64,7 +68,7 @@ def test__clear_context(choco_path): } with patch.dict(chocolatey.__context__, context): chocolatey._clear_context() - # Did it clear all chocolatey items from __context__? + # Did it clear all chocolatey items from __context__P? assert chocolatey.__context__ == {} @@ -329,27 +333,3 @@ def test_list_windowsfeatures_post_2_0_0(): chocolatey.list_windowsfeatures() expected_call = [choco_path, "search", "--source", "windowsfeatures"] mock_run.assert_called_with(expected_call, python_shell=False) - - -def test_chocolatey_version(): - context = { - "chocolatey._version": "0.9.9", - } - with patch.dict(chocolatey.__context__, context): - result = chocolatey.chocolatey_version() - expected = "0.9.9" - assert result == expected - - -def test_chocolatey_version_refresh(): - context = {"chocolatey._version": "0.9.9"} - mock_find = MagicMock(return_value="some_path") - mock_run = MagicMock(return_value="2.2.0") - with ( - patch.dict(chocolatey.__context__, context), - patch.object(chocolatey, "_find_chocolatey", mock_find), - patch.dict(chocolatey.__salt__, {"cmd.run": mock_run}), - ): - result = chocolatey.chocolatey_version(refresh=True) - expected = "2.2.0" - assert result == expected From bc36e7a82c3e14fe0afceebd9e617bd0f2a7a3fd Mon Sep 17 00:00:00 2001 From: Pedro Algarvio Date: Wed, 3 Apr 2024 08:59:43 +0100 Subject: [PATCH 9/9] Remove extra logic missed in 68131ce7ab248255feb50436a8b1c6c44813c762 This allowed the tests in https://github.com/saltstack/salt/pull/66169 to pass when they shouldn't --- .github/workflows/test-action-macos.yml | 2 +- .github/workflows/test-action-windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-action-macos.yml b/.github/workflows/test-action-macos.yml index d9b6cf52611..a6c1bd0b613 100644 --- a/.github/workflows/test-action-macos.yml +++ b/.github/workflows/test-action-macos.yml @@ -172,7 +172,7 @@ jobs: - name: Run Changed Tests id: run-fast-changed-tests - if: ${{ fromJSON(inputs.testrun)['type'] != 'full' && fromJSON(inputs.testrun)['selected_tests']['fast'] == false }} + if: ${{ fromJSON(inputs.testrun)['type'] != 'full' }} env: SKIP_REQUIREMENTS_INSTALL: "1" PRINT_TEST_SELECTION: "0" diff --git a/.github/workflows/test-action-windows.yml b/.github/workflows/test-action-windows.yml index c3ad353c3d1..488bac9a136 100644 --- a/.github/workflows/test-action-windows.yml +++ b/.github/workflows/test-action-windows.yml @@ -199,7 +199,7 @@ jobs: - name: Run Changed Tests id: run-fast-changed-tests - if: ${{ fromJSON(inputs.testrun)['type'] != 'full' && fromJSON(inputs.testrun)['selected_tests']['fast'] == false }} + if: ${{ fromJSON(inputs.testrun)['type'] != 'full' }} run: | tools --timestamps --no-output-timeout-secs=1800 --timeout-secs=14400 vm test --skip-requirements-install \ --nox-session=${{ inputs.nox-session }} --rerun-failures -E SALT_TRANSPORT ${{ matrix.fips && '--fips ' || '' }}${{ inputs.distro-slug }} \