Sign me up Login

Details about package ruby-chef-utils

Name: ruby-chef-utils (PTS)
Uploader: Norwid Behrnd <nbehrnd@protonmail.com> (Debian QA page)
Description: ruby-chef-utils - Basic utility functions for Core Chef Infra development

Package uploads

Upload #7

Information

Version: 16.12.3-3.1
Uploaded: 2026-06-11 13:06
Source package: ruby-chef-utils_16.12.3-3.1.dsc
Distribution: unstable
Section: ruby
Priority: optional
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467

Changelog

 ruby-chef-utils (16.12.3-3.1) unstable; urgency=medium
 .
   * Non-maintainer upload.
   * Constrain dependencies' versions, their admission to Debian
     must be prior to 16 Dec 2025 (Closes: #1123467).

QA information

Comments

  1. This upload freezes the dependencies in d/control to close the RC bug.  No additional edits, no upstream update.  The corresponding public repository is https://salsa.debian.org/nbehrnd/ruby-chef-utils_pinned_dependencies.  The report by `nmudiff --non-dd --no-mutt` is below.
    
    ----
    
    From: Norwid Behrnd <nbehrnd@protonmail.com>
    To:   1123467@bugs.debian.org
    Cc:   1134471@bugs.debian.org
    Bcc: 
    Subject: ruby-chef-utils: diff for NMU version 16.12.3-3.1
    Date: Thu, 11 Jun 2026 15:36:44 +0200
    X-NMUDIFF-Version: 2.26.7
    
    Control: tags 1123467 + patch
    Control: tags 1123467 + pending
    
    
    Dear maintainer,
    
    I've prepared an NMU for ruby-chef-utils (versioned as 16.12.3-3.1). The diff
    is attached to this message.
    
    I require a sponsor to have it uploaded.
    
    Regards.
    
    diffstat for ruby-chef-utils-16.12.3 ruby-chef-utils-16.12.3
    
     changelog    |    8 ++++++++
     control      |    6 +++---
     gbp.conf     |    4 ++++
     salsa-ci.yml |    3 +--
     4 files changed, 16 insertions(+), 5 deletions(-)
    
    diff -Nru ruby-chef-utils-16.12.3/debian/changelog ruby-chef-utils-16.12.3/debian/changelog
    --- ruby-chef-utils-16.12.3/debian/changelog	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-16.12.3/debian/changelog	2026-06-11 14:32:26.000000000 +0200
    @@ -1,3 +1,11 @@
    +ruby-chef-utils (16.12.3-3.1) unstable; urgency=medium
    +
    +  * Non-maintainer upload.
    +  * Constrain dependencies' versions, their admission to Debian
    +    must be prior to 16 Dec 2025 (Closes: #1123467).
    +
    + -- Norwid Behrnd <nbehrnd@protonmail.com>  Thu, 11 Jun 2026 14:32:26 +0200
    +
     ruby-chef-utils (16.12.3-3) unstable; urgency=medium
     
       * Team upload.
    diff -Nru ruby-chef-utils-16.12.3/debian/control ruby-chef-utils-16.12.3/debian/control
    --- ruby-chef-utils-16.12.3/debian/control	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-16.12.3/debian/control	2026-06-11 14:32:26.000000000 +0200
    @@ -5,9 +5,9 @@
     Uploaders: Pirate Praveen <praveen@debian.org>
     Build-Depends: debhelper-compat (= 13),
                    gem2deb (>= 1),
    -               rake,
    -               ruby-rspec,
    -               ruby-fauxhai
    +               rake (<= 13.3.1-1),
    +               ruby-rspec (<= 3.13.2c6e5m8s7-1),
    +               ruby-fauxhai (<= 9.3.0-1)
     Standards-Version: 4.7.2
     Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
     Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
    diff -Nru ruby-chef-utils-16.12.3/debian/gbp.conf ruby-chef-utils-16.12.3/debian/gbp.conf
    --- ruby-chef-utils-16.12.3/debian/gbp.conf	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-16.12.3/debian/gbp.conf	2026-06-11 14:28:18.000000000 +0200
    @@ -0,0 +1,4 @@
    +[DEFAULT]
    +debian-branch = debian/latest
    +upstream-branch = upstream/latest
    +pristine-tar = True
    diff -Nru ruby-chef-utils-16.12.3/debian/salsa-ci.yml ruby-chef-utils-16.12.3/debian/salsa-ci.yml
    --- ruby-chef-utils-16.12.3/debian/salsa-ci.yml	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-16.12.3/debian/salsa-ci.yml	2026-06-11 14:28:18.000000000 +0200
    @@ -1,4 +1,3 @@
     ---
     include:
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
    +  - https://salsa.debian.org/ruby-team/meta/raw/master/salsa-ci.yml
    Norwid Behrnd at June 11, 2026, 1:38 p.m.

Upload #6

Information

Version: 19.2.12-0.1
Uploaded: 2026-06-03 18:36
Source package: ruby-chef-utils_19.2.12-0.1.dsc
Distribution: unstable
Section: ruby
Priority: optional
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467 #1127665

Changelog

 ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
 .
   * Non-maintainer upload.
   * Manual upstream update and additional dependency (Closes: #1123467).
   * Reactivate d/watch (Closes: #1127665).

QA information

Comments

  1. Home of this upload is https://salsa.debian.org/nbehrnd/chef-utils_nmu_19p2p12_watch.  Building on the results of https://salsa.debian.org/nbehrnd/chef-utils_nmu_19p2p12 (only about the bug classified as release critical, see upload below) this now passes each of the d/salsa-ci.yml defined tests.
    Norwid Behrnd at June 3, 2026, 6:41 p.m.
  2. The overall inspection by nmudiff:
    
    X-NMUDIFF-Version: 2.26.7
    
    Control: tags 1123467 + patch
    Control: tags 1123467 + pending
    Control: tags 1127665 + patch
    Control: tags 1127665 + pending
    
    
    Dear maintainer,
    
    I've prepared an NMU for ruby-chef-utils (versioned as 19.2.12-0.1, deposited on https://mentors.debian.net/package/ruby-chef-utils/#upload-6). The diff
    is attached to this message.
    
    I require a sponsor to have it uploaded.
    
    Regards,
    Norwid
    
    diffstat for ruby-chef-utils-16.12.3 ruby-chef-utils-19.2.12
    
     chef-utils.gemspec                     |   16 ++-
     debian/changelog                       |    9 +
     debian/control                         |    1 
     debian/gbp.conf                        |    4 
     debian/salsa-ci.yml                    |    3 
     debian/watch                           |    4 
     lib/chef-utils.rb                      |    3 
     lib/chef-utils/dist.rb                 |   58 ++++++++++++
     lib/chef-utils/dsl/architecture.rb     |    2 
     lib/chef-utils/dsl/backend.rb          |   27 +++++
     lib/chef-utils/dsl/cloud.rb            |   44 ++++++---
     lib/chef-utils/dsl/default_paths.rb    |    2 
     lib/chef-utils/dsl/introspection.rb    |   13 ++
     lib/chef-utils/dsl/os.rb               |    2 
     lib/chef-utils/dsl/path_sanity.rb      |    2 
     lib/chef-utils/dsl/platform.rb         |   17 +++
     lib/chef-utils/dsl/platform_family.rb  |   22 ++++
     lib/chef-utils/dsl/platform_version.rb |    2 
     lib/chef-utils/dsl/service.rb          |    2 
     lib/chef-utils/dsl/train_helpers.rb    |    2 
     lib/chef-utils/dsl/virtualization.rb   |   35 +++++++
     lib/chef-utils/dsl/which.rb            |   12 +-
     lib/chef-utils/dsl/windows.rb          |    4 
     lib/chef-utils/internal.rb             |    6 -
     lib/chef-utils/mash.rb                 |   23 ++++
     lib/chef-utils/parallel_map.rb         |  131 +++++++++++++++++++++++++++
     lib/chef-utils/version.rb              |    4 
     spec/unit/dsl/architecture_spec.rb     |    2 
     spec/unit/dsl/cloud_spec.rb            |   11 +-
     spec/unit/dsl/dsl_spec.rb              |    2 
     spec/unit/dsl/introspection_spec.rb    |   14 ++
     spec/unit/dsl/os_spec.rb               |    2 
     spec/unit/dsl/path_sanity_spec.rb      |    4 
     spec/unit/dsl/platform_family_spec.rb  |   34 ++++---
     spec/unit/dsl/platform_spec.rb         |   16 +++
     spec/unit/dsl/service_spec.rb          |    2 
     spec/unit/dsl/virtualization_spec.rb   |    6 -
     spec/unit/dsl/which_spec.rb            |    2 
     spec/unit/dsl/windows_spec.rb          |    2 
     spec/unit/mash_spec.rb                 |    2 
     spec/unit/parallel_map_spec.rb         |  156 +++++++++++++++++++++++++++++++++
     41 files changed, 631 insertions(+), 74 deletions(-)
    
    diff -Nru ruby-chef-utils-16.12.3/chef-utils.gemspec ruby-chef-utils-19.2.12/chef-utils.gemspec
    --- ruby-chef-utils-16.12.3/chef-utils.gemspec	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/chef-utils.gemspec	2026-06-03 12:04:51.000000000 +0200
    @@ -10,17 +10,17 @@
       spec.email         = ["oss@chef.io"]
     
       spec.summary       = %q{Basic utility functions for Core Chef Infra development}
    -  spec.homepage      = "https://github.com/chef/chef/tree/master/chef-utils"
    +  spec.homepage      = "https://github.com/chef/chef/tree/main/chef-utils"
       spec.license       = "Apache-2.0"
     
    -  spec.required_ruby_version = ">= 2.6.0"
    +  spec.required_ruby_version = ">= 2.6"
     
       spec.metadata = {
         "bug_tracker_uri" => "https://github.com/chef/chef/issues",
    -    "changelog_uri" => "https://github.com/chef/chef/blob/master/CHANGELOG.md",
    -    "documentation_uri" => "https://github.com/chef/chef/tree/master/chef-utils/README.md",
    -    "homepage_uri" => "https://github.com/chef/chef/tree/master/chef-utils",
    -    "source_code_uri" => "https://github.com/chef/chef/tree/master/chef-utils",
    +    "changelog_uri" => "https://github.com/chef/chef/blob/main/CHANGELOG.md",
    +    "documentation_uri" => "https://github.com/chef/chef/tree/main/chef-utils/README.md",
    +    "homepage_uri" => "https://github.com/chef/chef/tree/main/chef-utils",
    +    "source_code_uri" => "https://github.com/chef/chef/tree/main/chef-utils",
       }
     
       spec.require_paths = ["lib"]
    @@ -41,6 +41,10 @@
       # ABSOLUTELY NO EXCEPTIONS
       #
     
    +  # concurrent-ruby is: 1. lightweight, 2. has zero deps, 3. is external to chef
    +  # this is used for the parallel_map enumerable extension for lightweight threading
    +  spec.add_dependency "concurrent-ruby"
    +
       spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
         Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
     end
    diff -Nru ruby-chef-utils-16.12.3/debian/changelog ruby-chef-utils-19.2.12/debian/changelog
    --- ruby-chef-utils-16.12.3/debian/changelog	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/changelog	2026-06-03 15:13:03.000000000 +0200
    @@ -1,3 +1,11 @@
    +ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
    +
    +  * Non-maintainer upload.
    +  * Manual upstream update and additional dependency (Closes: #1123467).
    +  * Reactivate d/watch (Closes: #1127665).
    +
    + -- Norwid Behrnd <nbehrnd@protonmail.com>  Wed, 03 Jun 2026 15:13:03 +0200
    +
     ruby-chef-utils (16.12.3-3) unstable; urgency=medium
     
       * Team upload.
    @@ -13,6 +21,7 @@
     
      -- Lucas Kanashiro <kanashiro@debian.org>  Thu, 08 May 2025 09:16:26 -0300
     
    +
     ruby-chef-utils (16.12.3-2) unstable; urgency=medium
     
       * Source-only upload for migration to testing
    diff -Nru ruby-chef-utils-16.12.3/debian/control ruby-chef-utils-19.2.12/debian/control
    --- ruby-chef-utils-16.12.3/debian/control	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/control	2026-06-03 15:13:03.000000000 +0200
    @@ -6,6 +6,7 @@
     Build-Depends: debhelper-compat (= 13),
                    gem2deb (>= 1),
                    rake,
    +               ruby-concurrent,
                    ruby-rspec,
                    ruby-fauxhai
     Standards-Version: 4.7.2
    diff -Nru ruby-chef-utils-16.12.3/debian/gbp.conf ruby-chef-utils-19.2.12/debian/gbp.conf
    --- ruby-chef-utils-16.12.3/debian/gbp.conf	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/debian/gbp.conf	2026-06-03 15:13:03.000000000 +0200
    @@ -0,0 +1,4 @@
    +[DEFAULT]
    +debian-branch = debian/latest
    +upstream-branch = upstream/latest
    +pristine-tar = True
    diff -Nru ruby-chef-utils-16.12.3/debian/salsa-ci.yml ruby-chef-utils-19.2.12/debian/salsa-ci.yml
    --- ruby-chef-utils-16.12.3/debian/salsa-ci.yml	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/salsa-ci.yml	2026-06-03 15:13:03.000000000 +0200
    @@ -1,4 +1,3 @@
     ---
     include:
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
    +  - https://salsa.debian.org/ruby-team/meta/raw/master/salsa-ci.yml
    diff -Nru ruby-chef-utils-16.12.3/debian/watch ruby-chef-utils-19.2.12/debian/watch
    --- ruby-chef-utils-16.12.3/debian/watch	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/watch	2026-06-03 15:13:03.000000000 +0200
    @@ -1,3 +1,3 @@
    -#version=4
    -#https://gemwatch.debian.net/chef-utils .*/chef-utils-(.*).tar.gz
    +version=4
    +https://gemwatch.debian.net/chef-utils .*/chef-utils-(.*).tar.gz
     # See README.Source for downloading the gem from cinc project
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dist.rb ruby-chef-utils-19.2.12/lib/chef-utils/dist.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dist.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dist.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -15,6 +15,25 @@
           PRODUCT = "Chef Automate"
         end
     
    +    class Cli
    +      # the chef-cli product name
    +      PRODUCT = "Chef CLI"
    +
    +      # the chef-cli gem
    +      GEM = "chef-cli"
    +    end
    +
    +    class Habitat
    +      # name of the Habitat product
    +      PRODUCT = "Chef Habitat"
    +
    +      # A short designation for the product
    +      SHORT = "habitat"
    +
    +      # The hab cli binary
    +      EXEC = "hab"
    +    end
    +
         class Infra
           # When referencing a product directly, like Chef (Now Chef Infra)
           PRODUCT = "Chef Infra Client"
    @@ -42,6 +61,20 @@
           # The suffix for Chef's /etc/chef, /var/chef and C:\\Chef directories
           # "chef" => /etc/cinc, /var/cinc, C:\\cinc
           DIR_SUFFIX = "chef"
    +
    +      # The client's gem
    +      GEM = "chef"
    +
    +      # The client's container image
    +      CONTAINER_REF = "chef/chef-hab"
    +    end
    +
    +    class Inspec
    +      # The InSpec product name
    +      PRODUCT = "Chef InSpec"
    +
    +      # The inspec binary
    +      EXEC = "inspec"
         end
     
         class Org
    @@ -49,7 +82,7 @@
           WEBSITE = "https://chef.io"
     
           # The downloads site
    -      DOWNLOADS_URL = "downloads.chef.io"
    +      DOWNLOADS_URL = "chef.io/downloads"
     
           # The legacy conf folder: C:/opscode/chef. Specifically the "opscode" part
           # DIR_SUFFIX is appended to it in code where relevant
    @@ -63,6 +96,12 @@
     
           # knife documentation page
           KNIFE_DOCS = "https://docs.chef.io/workstation/knife/"
    +
    +      # the name of the overall infra product
    +      PRODUCT = "Chef Infra"
    +
    +      # Omnitruck URL
    +      OMNITRUCK_URL = "https://omnitruck.chef.io/install.sh"
         end
     
         class Server
    @@ -77,6 +116,12 @@
     
           # The server's configuration utility
           SERVER_CTL = "chef-server-ctl"
    +
    +      # The server`s docs URL
    +      SERVER_DOCS = "https://docs.chef.io/server/"
    +
    +      # OS user for server
    +      SYSTEM_USER = "opscode"
         end
     
         class Solo
    @@ -87,6 +132,17 @@
           EXEC = "chef-solo"
         end
     
    +    class Workstation
    +      # The full marketing name of the product
    +      PRODUCT = "Chef Workstation"
    +
    +      # The suffix for Chef Workstation's /opt/chef-workstation or C:\\opscode\chef-workstation
    +      DIR_SUFFIX = "chef-workstation"
    +
    +      # Workstation banner/help text
    +      DOCS = "https://docs.chef.io/workstation/"
    +    end
    +
         class Zero
           # chef-zero executable
           PRODUCT = "Chef Infra Zero"
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/architecture.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/architecture.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/architecture.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/architecture.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/backend.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/backend.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/backend.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/backend.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,27 @@
    +module ChefUtils
    +  module DSL
    +    module Backend
    +      include Internal
    +
    +      # Determine if the backend is local
    +      #
    +      # @param [Chef::Node] node the node to check
    +      #
    +      # @return [Boolean]
    +      #
    +      def local_mode?
    +        node["platform_backend"] == "local"
    +      end
    +
    +      # Determine if the backend is remote
    +      #
    +      # @param [Chef::Node] node the node to check
    +      #
    +      # @return [Boolean]
    +      #
    +      def target_mode?
    +        node["platform_backend"] != "local"
    +      end
    +    end
    +  end
    +end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/cloud.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/cloud.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/cloud.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/cloud.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -23,7 +23,7 @@
         module Cloud
           include Internal
     
    -      # Determine if the current node is "in the cloud".
    +      # Determine if the current node is running in a known cloud.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -35,7 +35,18 @@
             !node["cloud"].nil?
           end
     
    -      # Return true if the current current node is in EC2.
    +      # Determine if the current node is running in Alibaba Cloud
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def alibaba?(node = __getnode)
    +        node.key?("alibaba")
    +      end
    +
    +      # Determine if the current node is running in AWS EC2.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -46,7 +57,7 @@
             node.key?("ec2")
           end
     
    -      # Return true if the current current node is in GCE.
    +      # Determine if the current node running in Google Compute Engine (GCE).
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -57,7 +68,7 @@
             node.key?("gce")
           end
     
    -      # Return true if the current current node is in Rackspace.
    +      # Determine if the current node is running in Rackspace.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -68,7 +79,7 @@
             node.key?("rackspace")
           end
     
    -      # Return true if the current current node is in Eucalyptus.
    +      # Determine if the current node is running in Eucalyptus.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -81,7 +92,7 @@
           # chef-sugar backcompat method
           alias_method :euca?, :eucalyptus?
     
    -      # Return true if the current current node is in Linode.
    +      # Determine if the current node is running in Linode.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -92,7 +103,7 @@
             node.key?("linode")
           end
     
    -      # Return true if the current current node is in OpenStack.
    +      # Determine if the current node is running in OpenStack.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -103,7 +114,7 @@
             node.key?("openstack")
           end
     
    -      # Return true if the current current node is in Azure.
    +      # Determine if the current node is running in Microsoft Azure.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -114,7 +125,7 @@
             node.key?("azure")
           end
     
    -      # Return true if the current current node is in DigitalOcean.
    +      # Determine if the current node is running in DigitalOcean.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -127,7 +138,7 @@
           # chef-sugar backcompat method
           alias_method :digitalocean?, :digital_ocean?
     
    -      # Return true if the current current node is in SoftLayer.
    +      # Determine if the current node is running in SoftLayer (IBM Cloud).
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -138,6 +149,17 @@
             node.key?("softlayer")
           end
     
    +      # Determine if the current node is running in Oracle Cloud Infrastructure (OCI).
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 19.1
    +      #
    +      # @return [Boolean]
    +      #
    +      def oci?(node = __getnode)
    +        node.key?("oci")
    +      end
    +
           extend self
         end
       end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/default_paths.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/default_paths.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/default_paths.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/default_paths.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/introspection.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/introspection.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/introspection.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/introspection.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -29,6 +29,17 @@
         module Introspection
           include TrainHelpers
     
    +      # Determine if the node is using the Chef Effortless pattern in which the Chef Infra Client is packaged using Chef Habitat
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def effortless?(node = __getnode)
    +        !!(node && node.read("chef_packages", "chef", "chef_effortless"))
    +      end
    +
           # Determine if the node is a docker container.
           #
           # @param [Chef::Node] node the node to check
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/os.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/os.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/os.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/os.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/path_sanity.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/path_sanity.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/path_sanity.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/path_sanity.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_family.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_family.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_family.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_family.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -77,7 +77,7 @@
           # @return [Boolean]
           #
           def macos?(node = __getnode)
    -        node["platform_family"] == "mac_os_x"
    +        node ? node["platform_family"] == "mac_os_x" : macos_ruby?
           end
           # chef-sugar backcompat method
           alias_method :osx?, :macos?
    @@ -86,6 +86,17 @@
           # chef-sugar backcompat method
           alias_method :mac_os_x?, :macos?
     
    +      # Determine if the Ruby VM is currently running on a Mac node (This is useful primarily for internal use
    +      # by Chef Infra Client before the node object exists).
    +      #
    +      # @since 17.3
    +      #
    +      # @return [Boolean]
    +      #
    +      def macos_ruby?
    +        !!(RUBY_PLATFORM =~ /darwin/)
    +      end
    +
           # Determine if the current node is a member of the 'rhel' platform family (Red Hat, CentOS, Oracle or Scientific Linux, but NOT Amazon Linux or Fedora).
           #
           # @param [Chef::Node] node the node to check
    @@ -259,12 +270,17 @@
           # Determine if the Ruby VM is currently running on a Windows node (ChefSpec can never stub
           # this behavior, so this is useful for code which can never be parsed on a non-Windows box).
           #
    +      # April 2022 - Note that we changed the platform identifier from 'mingw32' to 'mingw'
    +      # We did this because Ruby 3.1 introduces the new universal windows platform of 'x64-mingw-ucrt'
    +      # We updated the existing regex snippet to capture both the 32-bit platform and the new x64
    +      # universal platform
    +      #
           # @since 15.5
           #
           # @return [Boolean]
           #
           def windows_ruby?
    -        !!(RUBY_PLATFORM =~ /mswin|mingw32|windows/)
    +        !!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
           end
     
           #
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -123,6 +123,21 @@
           # chef-sugar backcompat method
           alias_method :centos?, :centos_platform?
     
    +      # Determine if the current node is CentOS Stream.
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def centos_stream_platform?(node = __getnode)
    +        if node["os_release"]
    +          node.dig("os_release", "name") == "CentOS Stream"
    +        else
    +          node.dig("lsb", "id") == "CentOSStream"
    +        end
    +      end
    +
           # Determine if the current node is Oracle Linux.
           #
           # @param [Chef::Node] node the node to check
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_version.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_version.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_version.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_version.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/service.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/service.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/service.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/service.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/train_helpers.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/train_helpers.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/train_helpers.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/train_helpers.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/virtualization.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/virtualization.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/virtualization.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/virtualization.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -140,6 +140,28 @@
             node.dig("virtualization", "system") == "vmware" && node.dig("virtualization", "role") == "host"
           end
     
    +      # Determine if the current node is virtualized on VMware Desktop (Fusion/Player/Workstation).
    +      #
    +      # @param [Chef::Node] node
    +      # @since 17.9
    +      #
    +      # @return [Boolean]
    +      #
    +      def vmware_desktop?(node = __getnode)
    +        node.dig("virtualization", "system") == "vmware" && node.dig("vmware", "host", "type") == "vmware_desktop"
    +      end
    +
    +      # Determine if the current node is virtualized on VMware vSphere (ESX).
    +      #
    +      # @param [Chef::Node] node
    +      # @since 17.9
    +      #
    +      # @return [Boolean]
    +      #
    +      def vmware_vsphere?(node = __getnode)
    +        node.dig("virtualization", "system") == "vmware" && node.dig("vmware", "host", "type") == "vmware_vsphere"
    +      end
    +
           # Determine if the current node is an openvz guest.
           #
           # @param [Chef::Node] node
    @@ -162,6 +184,17 @@
             node.dig("virtualization", "system") == "openvz" && node.dig("virtualization", "role") == "host"
           end
     
    +      # Determine if the current node is running under Microsoft Hyper-v.
    +      #
    +      # @param [Chef::Node] node
    +      # @since 18.5
    +      #
    +      # @return [Boolean]
    +      #
    +      def hyperv?(node = __getnode)
    +        node.dig("virtualization", "system") == "hyperv" && node.dig("virtualization", "role") == "guest"
    +      end
    +
           # Determine if the current node is running under any virtualization environment
           #
           # @param [Chef::Node] node
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/which.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/which.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/which.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/which.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -46,11 +46,12 @@
           #   end
           #
           # @param [Array<String>] list of commands to search for
    +      # @param [String,Array<String>] array of paths to look in first
           # @param [String,Array<String>] array of extra paths to search through
           # @return [String] the first match
           #
    -      def which(*cmds, extra_path: nil, &block)
    -        where(*cmds, extra_path: extra_path, &block).first || false
    +      def which(*cmds, prepend_path: nil, extra_path: nil, &block)
    +        where(*cmds, prepend_path: prepend_path, extra_path: extra_path, &block).first || false
           end
     
           # Lookup all the instances of an an executable that can be found through the systems search PATH.
    @@ -73,12 +74,13 @@
           #   end
           #
           # @param [Array<String>] list of commands to search for
    +      # @param [String,Array<String>] array of paths to look in first
           # @param [String,Array<String>] array of extra paths to search through
           # @return [String] the first match
           #
    -      def where(*cmds, extra_path: nil, &block)
    +      def where(*cmds, prepend_path: nil, extra_path: nil, &block)
             extra_path ||= __extra_path
    -        paths = __env_path.split(File::PATH_SEPARATOR) + Array(extra_path)
    +        paths = Array(prepend_path) + __env_path.split(File::PATH_SEPARATOR) + Array(extra_path)
             paths.uniq!
             exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : []
             exts.unshift("")
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/windows.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/windows.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/windows.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/windows.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -58,7 +58,7 @@
             node["kernel"]["product_type"] == "Server"
           end
     
    -      # Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. IE: NT 6.3 is Windows 8.1 and Windows 2012 R2.
    +      # Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. For example NT 6.3 corresponds to Windows 8.1 and Windows 2012 R2.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/internal.rb ruby-chef-utils-19.2.12/lib/chef-utils/internal.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/internal.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/internal.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -70,7 +70,7 @@
         #
         def __env_path
           if __transport_connection
    -        __transport_connection.run_command("echo $PATH").stdout || ""
    +        __transport_connection.run_command("echo $PATH").stdout.chomp || ""
           else
             ENV["PATH"] || ""
           end
    @@ -84,7 +84,7 @@
         #
         def __transport_connection
           # Software consumers MUST override this method with their own implementation.  The default behavior here is subject to change.
    -      return Chef.run_context.transport_connection if defined?(Chef) && Chef.respond_to?(:run_context) && Chef&.run_context&.transport_connection
    +      return Chef.run_context.transport_connection if defined?(Chef) && Chef.respond_to?(:run_context) && Chef.run_context&.transport_connection
     
           nil
         end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/mash.rb ruby-chef-utils-19.2.12/lib/chef-utils/mash.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/mash.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/mash.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -94,6 +94,10 @@
           end
         end
     
    +    unless method_defined?(:regular_reader)
    +      alias_method :regular_reader, :[]
    +    end
    +
         unless method_defined?(:regular_writer)
           alias_method :regular_writer, :[]=
         end
    @@ -102,6 +106,19 @@
           alias_method :regular_update, :update
         end
     
    +    unless method_defined?(:regular_clear)
    +      alias_method :regular_clear, :clear
    +    end
    +
    +    unless method_defined?(:regular_delete)
    +      alias_method :regular_delete, :delete
    +    end
    +
    +    # @param key<Object> The key to get.
    +    def [](key)
    +      regular_reader(key)
    +    end
    +
         # @param key<Object> The key to set.
         # @param value<Object>
         #   The value to set the key to.
    @@ -113,6 +130,12 @@
         end
     
         # internal API for use by Chef's deep merge cache
    +    # @api private
    +    def internal_get(key)
    +      regular_reader(key)
    +    end
    +
    +    # internal API for use by Chef's deep merge cache
         # @api private
         def internal_set(key, value)
           regular_writer(key, convert_value(value))
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/parallel_map.rb ruby-chef-utils-19.2.12/lib/chef-utils/parallel_map.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/parallel_map.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/parallel_map.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,131 @@
    +# frozen_string_literal: true
    +#
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
    +# License:: Apache License, Version 2.0
    +#
    +# Licensed under the Apache License, Version 2.0 (the "License");
    +# you may not use this file except in compliance with the License.
    +# You may obtain a copy of the License at
    +#
    +#     http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing, software
    +# distributed under the License is distributed on an "AS IS" BASIS,
    +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +# See the License for the specific language governing permissions and
    +# limitations under the License.
    +#
    +
    +require "concurrent/executors"
    +require "concurrent/future"
    +require "singleton" unless defined?(Singleton)
    +
    +module ChefUtils
    +  #
    +  # This module contains ruby refinements that adds several methods to the Enumerable
    +  # class which are useful for parallel processing.
    +  #
    +  module ParallelMap
    +    refine Enumerable do
    +
    +      # Enumerates through the collection in parallel using the thread pool provided
    +      # or the default thread pool.  By using the default thread pool this supports
    +      # recursively calling the method without deadlocking while using a globally
    +      # fixed number of workers.  This method supports lazy collections.  It returns
    +      # synchronously, waiting until all the work is done.  Failures are only reported
    +      # after the collection has executed and only the first exception is raised.
    +      #
    +      # (0..).lazy.parallel_map { |i| i*i }.first(5)
    +      #
    +      # @return [Array] output results
    +      #
    +      def parallel_map(pool: nil)
    +        return self unless block_given?
    +
    +        pool ||= ChefUtils::DefaultThreadPool.instance.pool
    +
    +        futures = map do |item|
    +          Concurrent::Future.execute(executor: pool) do
    +            yield item
    +          end
    +        end
    +
    +        futures.map(&:value!)
    +      end
    +
    +      # This has the same behavior as parallel_map but returns the enumerator instead of
    +      # the return values.
    +      #
    +      # @return [Enumerable] the enumerable for method chaining
    +      #
    +      def parallel_each(pool: nil, &block)
    +        return self unless block_given?
    +
    +        parallel_map(pool: pool, &block)
    +
    +        self
    +      end
    +
    +      # The flat_each method is tightly coupled to the usage of parallel_map within the
    +      # ChefFS implementation.  It is not itself a parallel method, but it is used to
    +      # iterate through the 2nd level of nested structure, which is tied to the nested
    +      # structures that ChefFS returns.
    +      #
    +      # This is different from Enumerable#flat_map because that behaves like map.flatten(1) while
    +      # this behaves more like flatten(1).each.  We need this on an Enumerable, so we have no
    +      # Enumerable#flatten method to call.
    +      #
    +      # [ [ 1, 2 ], [ 3, 4 ] ].flat_each(&block) calls block four times with 1, 2, 3, 4
    +      #
    +      # [ [ 1, 2 ], [ 3, 4 ] ].flat_map(&block) calls block twice with [1, 2] and [3,4]
    +      #
    +      def flat_each(&block)
    +        map do |value|
    +          if value.is_a?(Enumerable)
    +            value.each(&block)
    +          else
    +            yield value
    +          end
    +        end
    +      end
    +    end
    +  end
    +
    +  # The DefaultThreadPool has a fixed thread size and has no
    +  # queue of work and the behavior on failure to find a thread is for the
    +  # caller to run the work.  This contract means that the thread pool can
    +  # be called recursively without deadlocking and while keeping the fixed
    +  # number of threads (and not exponentially growing the thread pool with
    +  # the depth of recursion).
    +  #
    +  class DefaultThreadPool
    +    include Singleton
    +
    +    DEFAULT_THREAD_SIZE = 10
    +
    +    # Size of the thread pool, must be set before getting the thread pool or
    +    # calling parallel_map/parallel_each.  Does not (but could be modified to)
    +    # support dynamic resizing. To get fully synchronous behavior set this equal to
    +    # zero rather than one since the caller will get work if the threads are
    +    # busy.
    +    #
    +    # @return [Integer] number of threads
    +    attr_accessor :threads
    +
    +    # Memoizing accessor for the thread pool
    +    #
    +    # @return [Concurrent::ThreadPoolExecutor] the thread pool
    +    def pool
    +      @pool ||= Concurrent::ThreadPoolExecutor.new(
    +        min_threads: threads || DEFAULT_THREAD_SIZE,
    +        max_threads: threads || DEFAULT_THREAD_SIZE,
    +        max_queue: 0,
    +        # "synchronous" redefines the 0 in max_queue to mean 'no queue' instead of 'infinite queue'
    +        # it does not mean synchronous execution (no threads) but synchronous offload to the threads.
    +        synchronous: true,
    +        # this prevents deadlocks on recursive parallel usage
    +        fallback_policy: :caller_runs
    +      )
    +    end
    +  end
    +end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/version.rb ruby-chef-utils-19.2.12/lib/chef-utils/version.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/version.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/version.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,5 +1,5 @@
     # frozen_string_literal: true
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -16,5 +16,5 @@
     
     module ChefUtils
       CHEFUTILS_ROOT = File.expand_path("..", __dir__)
    -  VERSION = "16.12.3"
    +  VERSION = "19.2.12"
     end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils.rb ruby-chef-utils-19.2.12/lib/chef-utils.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,6 +17,7 @@
     #
     
     require_relative "chef-utils/dsl/architecture"
    +require_relative "chef-utils/dsl/backend"
     require_relative "chef-utils/dsl/cloud"
     require_relative "chef-utils/dsl/introspection"
     require_relative "chef-utils/dsl/os"
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/architecture_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/architecture_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/architecture_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/architecture_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/cloud_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/cloud_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/cloud_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/cloud_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,7 +17,6 @@
     #
     
     require "spec_helper"
    -require "fauxhai"
     
     def cloud_reports_true_for(*args, node:)
       args.each do |method|
    @@ -45,6 +44,10 @@
         end
       end
     
    +  context "on alibaba" do
    +    cloud_reports_true_for(:cloud?, :alibaba?, node: { "alibaba" => {}, "cloud" => {} })
    +  end
    +
       context "on ec2" do
         cloud_reports_true_for(:cloud?, :ec2?, node: { "ec2" => {}, "cloud" => {} })
       end
    @@ -81,6 +84,10 @@
         cloud_reports_true_for(:cloud?, :softlayer?, node: { "softlayer" => {}, "cloud" => {} })
       end
     
    +  context "on oci" do
    +    cloud_reports_true_for(:cloud?, :oci?, node: { "oci" => {}, "cloud" => {} })
    +  end
    +
       context "on virtualbox" do
         it "does not return true for cloud?" do
           expect(described_class.cloud?({ "virtualbox" => {}, "cloud" => nil })).to be false
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/dsl_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/dsl_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/dsl_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/dsl_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/introspection_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/introspection_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/introspection_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/introspection_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -32,6 +32,18 @@
     
       let(:test_instance) { IntrospectionTestClass.new(node) }
     
    +  context "#effortless?" do
    +    # FIXME: use a real VividMash for these tests instead of stubbing
    +    it "is false by default" do
    +      expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(nil)
    +      expect(ChefUtils.effortless?(node)).to be false
    +    end
    +    it "is true when ohai reports a effortless" do
    +      expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(true)
    +      expect(ChefUtils.effortless?(node)).to be true
    +    end
    +  end
    +
       context "#docker?" do
         # FIXME: use a real VividMash for these tests instead of stubbing
         it "is false by default" do
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/os_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/os_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/os_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/os_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/path_sanity_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/path_sanity_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/path_sanity_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/path_sanity_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -79,7 +79,7 @@
         end
     
         it "prepends to an existing path" do
    -      env = { "PATH" => '%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\\' }
    +      env = { "PATH" => "%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\" }
           expect(test_instance.default_paths(env)).to eql("#{Gem.bindir};#{RbConfig::CONFIG["bindir"]};%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\")
         end
       end
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/platform_family_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/platform_family_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/platform_family_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/platform_family_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -25,7 +25,7 @@
           expect(described_class.send(method, node)).to be true
         end
       end
    -  (PLATFORM_FAMILY_HELPERS - [ :windows_ruby? ] - args).each do |method|
    +  (PLATFORM_FAMILY_HELPERS - %i{windows_ruby? macos_ruby?} - args).each do |method|
         it "reports false for #{method}" do
           expect(described_class.send(method, node)).to be false
         end
    @@ -41,7 +41,7 @@
         end
       end
     
    -  ( PLATFORM_FAMILY_HELPERS - [ :windows_ruby? ]).each do |helper|
    +  ( PLATFORM_FAMILY_HELPERS - %i{windows_ruby? macos_ruby?}).each do |helper|
         it "has the #{helper} in the ChefUtils module" do
           expect(ChefUtils).to respond_to(helper)
         end
    @@ -90,13 +90,13 @@
       end
     
       context "on centos6" do
    -    let(:options) { { platform: "centos", version: "6.10" } }
    +    let(:options) { { platform: "centos", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on centos7" do
    -    let(:options) { { platform: "centos", version: "7.7.1908" } }
    +    let(:options) { { platform: "centos", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -108,7 +108,7 @@
       end
     
       context "on clearos7" do
    -    let(:options) { { platform: "clearos", version: "7.4" } }
    +    let(:options) { { platform: "clearos", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -156,25 +156,25 @@
       end
     
       context "on oracle6" do
    -    let(:options) { { platform: "oracle", version: "6.10" } }
    +    let(:options) { { platform: "oracle", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on oracle7" do
    -    let(:options) { { platform: "oracle", version: "7.6" } }
    +    let(:options) { { platform: "oracle", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
     
       context "on redhat6" do
    -    let(:options) { { platform: "redhat", version: "6.10" } }
    +    let(:options) { { platform: "redhat", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on redhat7" do
    -    let(:options) { { platform: "redhat", version: "7.6" } }
    +    let(:options) { { platform: "redhat", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -210,7 +210,7 @@
       end
     
       context "node-independent windows APIs" do
    -    if RUBY_PLATFORM.match?(/mswin|mingw32|windows/)
    +    if RUBY_PLATFORM.match?(/mswin|mingw|windows/)
           it "reports true for :windows_ruby?" do
             expect(described_class.windows_ruby?).to be true
           end
    @@ -220,4 +220,16 @@
           end
         end
       end
    +
    +  context "node-independent mac APIs" do
    +    if RUBY_PLATFORM.match?(/darwin/)
    +      it "reports true for :macos_ruby?" do
    +        expect(described_class.macos_ruby?).to be true
    +      end
    +    else
    +      it "reports false for :macos_ruby?" do
    +        expect(described_class.macos_ruby?).to be false
    +      end
    +    end
    +  end
     end
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/platform_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/platform_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/platform_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/platform_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -145,6 +145,20 @@
         platform_reports_true_for(:centos?, :centos_platform?)
       end
     
    +  context "on centos stream w/o os_release" do
    +    let(:options) { { platform: "centos" } }
    +    let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "lsb" => { "id" => "CentOSStream" }, "os_release" => nil } }
    +
    +    platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
    +  end
    +
    +  context "on centos stream w/ os_release" do
    +    let(:options) { { platform: "centos" } }
    +    let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "os_release" => { "name" => "CentOS Stream" } } }
    +
    +    platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
    +  end
    +
       context "on clearos" do
         let(:options) { { platform: "clearos" } }
     
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/service_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/service_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/service_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/service_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/virtualization_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/virtualization_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/virtualization_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/virtualization_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,7 +17,6 @@
     #
     
     require "spec_helper"
    -require "fauxhai"
     
     def virtualization_reports_true_for(*args, node:)
       args.each do |method|
    @@ -45,6 +44,9 @@
         end
       end
     
    +  context "on hyperv" do
    +    virtualization_reports_true_for(:guest?, :virtual?, :hyperv?, node: { "virtualization" => { "system" => "hyperv", "role" => "guest" } })
    +  end
       context "on kvm" do
         virtualization_reports_true_for(:guest?, :virtual?, :kvm?, node: { "virtualization" => { "system" => "kvm",  "role" => "guest" } })
         virtualization_reports_true_for(:hypervisor?, :physical?, :kvm_host?, node: { "virtualization" => { "system" => "kvm", "role" => "host" } })
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/which_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/which_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/which_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/which_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/windows_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/windows_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/windows_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/windows_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/mash_spec.rb ruby-chef-utils-19.2.12/spec/unit/mash_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/mash_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/mash_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,7 +1,7 @@
     # frozen_string_literal: true
     #
     # Author:: Matthew Kent (<mkent@magoazul.com>)
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/parallel_map_spec.rb ruby-chef-utils-19.2.12/spec/unit/parallel_map_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/parallel_map_spec.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/spec/unit/parallel_map_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,156 @@
    +# frozen_string_literal: true
    +#
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
    +# License:: Apache License, Version 2.0
    +#
    +# Licensed under the Apache License, Version 2.0 (the "License");
    +# you may not use this file except in compliance with the License.
    +# You may obtain a copy of the License at
    +#
    +#     http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing, software
    +# distributed under the License is distributed on an "AS IS" BASIS,
    +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +# See the License for the specific language governing permissions and
    +# limitations under the License.
    +#
    +
    +require "chef-utils/parallel_map"
    +
    +using ChefUtils::ParallelMap
    +
    +RSpec.describe ChefUtils::ParallelMap do
    +
    +  shared_examples_for "common parallel API tests" do
    +
    +    before(:each) do
    +      ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
    +      ChefUtils::DefaultThreadPool.instance.threads = threads
    +    end
    +
    +    after(:each) do
    +      ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
    +    end
    +
    +    it "parallel_map runs in parallel" do
    +      # this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
    +      val = threads + 1
    +      ret = []
    +      start = Time.now
    +      (1..val).parallel_map do |i|
    +        loop do
    +          if val == i
    +            ret << i
    +            val -= 1
    +            break
    +          end
    +          # we spin for quite awhile to wait for very slow testers if we have to
    +          if Time.now - start > 30
    +            raise "timed out; deadlocked due to lack of parallelization?"
    +          end
    +
    +          # need to sleep a tiny bit to let other threads schedule
    +          sleep 0.000001
    +        end
    +      end
    +      expected = (1..threads + 1).to_a.reverse
    +      expect(ret).to eql(expected)
    +    end
    +
    +    it "parallel_each runs in parallel" do
    +      # this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
    +      val = threads + 1
    +      ret = []
    +      start = Time.now
    +      (1..val).parallel_each do |i|
    +        loop do
    +          if val == i
    +            ret << i
    +            val -= 1
    +            break
    +          end
    +          # we spin for quite awhile to wait for very slow testers if we have to
    +          if Time.now - start > 30
    +            raise "timed out; deadlocked due to lack of parallelization?"
    +          end
    +
    +          # need to sleep a tiny bit to let other threads schedule
    +          sleep 0.000001
    +        end
    +      end
    +      expected = (1..threads + 1).to_a.reverse
    +      expect(ret).to eql(expected)
    +    end
    +
    +    it "parallel_map throws exceptions" do
    +      expect { (0..10).parallel_map { |i| raise "boom" } }.to raise_error(RuntimeError)
    +    end
    +
    +    it "parallel_each throws exceptions" do
    +      expect { (0..10).parallel_each { |i| raise "boom" } }.to raise_error(RuntimeError)
    +    end
    +
    +    it "parallel_map runs" do
    +      ans = Timeout.timeout(30) do
    +        (1..10).parallel_map { |i| i }
    +      end
    +      expect(ans).to eql((1..10).to_a)
    +    end
    +
    +    it "parallel_each runs" do
    +      Timeout.timeout(30) do
    +        (1..10).parallel_each { |i| i }
    +      end
    +    end
    +
    +    it "recursive parallel_map will not deadlock" do
    +      ans = Timeout.timeout(30) do
    +        (1..2).parallel_map { |i| (1..2).parallel_map { |i| i } }
    +      end
    +      expect(ans).to eql([[1, 2], [1, 2]])
    +    end
    +
    +    it "recursive parallel_each will not deadlock" do
    +      Timeout.timeout(30) do
    +        (1..2).parallel_each { |i| (1..2).parallel_each { |i| i } }
    +      end
    +    end
    +
    +    it "parallel_map is lazy" do
    +      ans = Timeout.timeout(30) do
    +        (1..).lazy.parallel_map { |i| i }.first(5)
    +      end
    +      expect(ans).to eql((1..5).to_a)
    +    end
    +
    +    it "parallel_each is lazy" do
    +      Timeout.timeout(30) do
    +        (1..).lazy.parallel_each { |i| i }.first(5)
    +      end
    +    end
    +  end
    +
    +  context "with 10 threads" do
    +    let(:threads) { 10 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "with 0 threads" do
    +    let(:threads) { 0 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "with 1 threads" do
    +    let(:threads) { 1 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "flat_each" do
    +    it "runs each over items which are nested one level" do
    +      sum = 0
    +      [ [ 1, 2 ], [3, 4]].flat_each { |i| sum += i }
    +      expect(sum).to eql(10)
    +    end
    +  end
    +end
    Ready Norwid Behrnd at June 6, 2026, 7:50 a.m.

Upload #5

Information

Version: 19.2.12-0.1
Uploaded: 2026-06-03 13:51
Source package: ruby-chef-utils_19.2.12-0.1.dsc
Distribution: unstable
Section: ruby
Priority: optional
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467

Changelog

 ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
 .
   * Non-maintainer upload.
   * Manual upstream update and additional dependency (Closes: #1123467).

QA information

Comments

  1. Home to this upload is https://salsa.debian.org/nbehrnd/chef-utils_nmu_19p2p12
    Norwid Behrnd at June 3, 2026, 2:40 p.m.
  2. I just run `nmudiff --non-dd --no-mutt` in the directory of this upload (i.e., only the upstream update without assistance of d/watch, and no edit/reactivation of d/watch).  Because I still want to test something different, this report for this upload 5 (by 2026-06-03 13:51) is not sent out as a NMU bug.
    
    ----
    
    From: Norwid Behrnd <nbehrnd@protonmail.com>
    To:   1123467@bugs.debian.org
    Cc:
    Bcc: 
    Subject: ruby-chef-utils: diff for NMU version 19.2.12-0.1
    Date: Thu, 11 Jun 2026 11:33:57 +0200
    X-NMUDIFF-Version: 2.26.7
    
    Control: tags 1123467 + patch
    Control: tags 1123467 + pending
    
    
    Dear maintainer,
    
    I've prepared an NMU for ruby-chef-utils (versioned as 19.2.12-0.1). The diff
    is attached to this message.
    
    I require a sponsor to have it uploaded.
    
    Regards.
    
    diffstat for ruby-chef-utils-16.12.3 ruby-chef-utils-19.2.12
    
     chef-utils.gemspec                     |   16 ++-
     debian/changelog                       |    8 +
     debian/control                         |    1 
     debian/gbp.conf                        |    4 
     debian/salsa-ci.yml                    |    3 
     lib/chef-utils.rb                      |    3 
     lib/chef-utils/dist.rb                 |   58 ++++++++++++
     lib/chef-utils/dsl/architecture.rb     |    2 
     lib/chef-utils/dsl/backend.rb          |   27 +++++
     lib/chef-utils/dsl/cloud.rb            |   44 ++++++---
     lib/chef-utils/dsl/default_paths.rb    |    2 
     lib/chef-utils/dsl/introspection.rb    |   13 ++
     lib/chef-utils/dsl/os.rb               |    2 
     lib/chef-utils/dsl/path_sanity.rb      |    2 
     lib/chef-utils/dsl/platform.rb         |   17 +++
     lib/chef-utils/dsl/platform_family.rb  |   22 ++++
     lib/chef-utils/dsl/platform_version.rb |    2 
     lib/chef-utils/dsl/service.rb          |    2 
     lib/chef-utils/dsl/train_helpers.rb    |    2 
     lib/chef-utils/dsl/virtualization.rb   |   35 +++++++
     lib/chef-utils/dsl/which.rb            |   12 +-
     lib/chef-utils/dsl/windows.rb          |    4 
     lib/chef-utils/internal.rb             |    6 -
     lib/chef-utils/mash.rb                 |   23 ++++
     lib/chef-utils/parallel_map.rb         |  131 +++++++++++++++++++++++++++
     lib/chef-utils/version.rb              |    4 
     spec/unit/dsl/architecture_spec.rb     |    2 
     spec/unit/dsl/cloud_spec.rb            |   11 +-
     spec/unit/dsl/dsl_spec.rb              |    2 
     spec/unit/dsl/introspection_spec.rb    |   14 ++
     spec/unit/dsl/os_spec.rb               |    2 
     spec/unit/dsl/path_sanity_spec.rb      |    4 
     spec/unit/dsl/platform_family_spec.rb  |   34 ++++---
     spec/unit/dsl/platform_spec.rb         |   16 +++
     spec/unit/dsl/service_spec.rb          |    2 
     spec/unit/dsl/virtualization_spec.rb   |    6 -
     spec/unit/dsl/which_spec.rb            |    2 
     spec/unit/dsl/windows_spec.rb          |    2 
     spec/unit/mash_spec.rb                 |    2 
     spec/unit/parallel_map_spec.rb         |  156 +++++++++++++++++++++++++++++++++
     40 files changed, 628 insertions(+), 72 deletions(-)
    
    diff -Nru ruby-chef-utils-16.12.3/chef-utils.gemspec ruby-chef-utils-19.2.12/chef-utils.gemspec
    --- ruby-chef-utils-16.12.3/chef-utils.gemspec	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/chef-utils.gemspec	2026-06-03 12:04:51.000000000 +0200
    @@ -10,17 +10,17 @@
       spec.email         = ["oss@chef.io"]
     
       spec.summary       = %q{Basic utility functions for Core Chef Infra development}
    -  spec.homepage      = "https://github.com/chef/chef/tree/master/chef-utils"
    +  spec.homepage      = "https://github.com/chef/chef/tree/main/chef-utils"
       spec.license       = "Apache-2.0"
     
    -  spec.required_ruby_version = ">= 2.6.0"
    +  spec.required_ruby_version = ">= 2.6"
     
       spec.metadata = {
         "bug_tracker_uri" => "https://github.com/chef/chef/issues",
    -    "changelog_uri" => "https://github.com/chef/chef/blob/master/CHANGELOG.md",
    -    "documentation_uri" => "https://github.com/chef/chef/tree/master/chef-utils/README.md",
    -    "homepage_uri" => "https://github.com/chef/chef/tree/master/chef-utils",
    -    "source_code_uri" => "https://github.com/chef/chef/tree/master/chef-utils",
    +    "changelog_uri" => "https://github.com/chef/chef/blob/main/CHANGELOG.md",
    +    "documentation_uri" => "https://github.com/chef/chef/tree/main/chef-utils/README.md",
    +    "homepage_uri" => "https://github.com/chef/chef/tree/main/chef-utils",
    +    "source_code_uri" => "https://github.com/chef/chef/tree/main/chef-utils",
       }
     
       spec.require_paths = ["lib"]
    @@ -41,6 +41,10 @@
       # ABSOLUTELY NO EXCEPTIONS
       #
     
    +  # concurrent-ruby is: 1. lightweight, 2. has zero deps, 3. is external to chef
    +  # this is used for the parallel_map enumerable extension for lightweight threading
    +  spec.add_dependency "concurrent-ruby"
    +
       spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
         Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
     end
    diff -Nru ruby-chef-utils-16.12.3/debian/changelog ruby-chef-utils-19.2.12/debian/changelog
    --- ruby-chef-utils-16.12.3/debian/changelog	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/changelog	2026-06-03 15:13:03.000000000 +0200
    @@ -1,3 +1,10 @@
    +ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
    +
    +  * Non-maintainer upload.
    +  * Manual upstream update and additional dependency (Closes: #1123467).
    +
    + -- Norwid Behrnd <nbehrnd@protonmail.com>  Wed, 03 Jun 2026 15:13:03 +0200
    +
     ruby-chef-utils (16.12.3-3) unstable; urgency=medium
     
       * Team upload.
    @@ -13,6 +20,7 @@
     
      -- Lucas Kanashiro <kanashiro@debian.org>  Thu, 08 May 2025 09:16:26 -0300
     
    +
     ruby-chef-utils (16.12.3-2) unstable; urgency=medium
     
       * Source-only upload for migration to testing
    diff -Nru ruby-chef-utils-16.12.3/debian/control ruby-chef-utils-19.2.12/debian/control
    --- ruby-chef-utils-16.12.3/debian/control	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/control	2026-06-03 15:13:03.000000000 +0200
    @@ -6,6 +6,7 @@
     Build-Depends: debhelper-compat (= 13),
                    gem2deb (>= 1),
                    rake,
    +               ruby-concurrent,
                    ruby-rspec,
                    ruby-fauxhai
     Standards-Version: 4.7.2
    diff -Nru ruby-chef-utils-16.12.3/debian/gbp.conf ruby-chef-utils-19.2.12/debian/gbp.conf
    --- ruby-chef-utils-16.12.3/debian/gbp.conf	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/debian/gbp.conf	2026-06-03 15:08:40.000000000 +0200
    @@ -0,0 +1,4 @@
    +[DEFAULT]
    +debian-branch = debian/latest
    +upstream-branch = upstream/latest
    +pristine-tar = True
    diff -Nru ruby-chef-utils-16.12.3/debian/salsa-ci.yml ruby-chef-utils-19.2.12/debian/salsa-ci.yml
    --- ruby-chef-utils-16.12.3/debian/salsa-ci.yml	2025-05-08 14:16:26.000000000 +0200
    +++ ruby-chef-utils-19.2.12/debian/salsa-ci.yml	2026-06-03 15:08:40.000000000 +0200
    @@ -1,4 +1,3 @@
     ---
     include:
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
    -  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
    +  - https://salsa.debian.org/ruby-team/meta/raw/master/salsa-ci.yml
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dist.rb ruby-chef-utils-19.2.12/lib/chef-utils/dist.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dist.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dist.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -15,6 +15,25 @@
           PRODUCT = "Chef Automate"
         end
     
    +    class Cli
    +      # the chef-cli product name
    +      PRODUCT = "Chef CLI"
    +
    +      # the chef-cli gem
    +      GEM = "chef-cli"
    +    end
    +
    +    class Habitat
    +      # name of the Habitat product
    +      PRODUCT = "Chef Habitat"
    +
    +      # A short designation for the product
    +      SHORT = "habitat"
    +
    +      # The hab cli binary
    +      EXEC = "hab"
    +    end
    +
         class Infra
           # When referencing a product directly, like Chef (Now Chef Infra)
           PRODUCT = "Chef Infra Client"
    @@ -42,6 +61,20 @@
           # The suffix for Chef's /etc/chef, /var/chef and C:\\Chef directories
           # "chef" => /etc/cinc, /var/cinc, C:\\cinc
           DIR_SUFFIX = "chef"
    +
    +      # The client's gem
    +      GEM = "chef"
    +
    +      # The client's container image
    +      CONTAINER_REF = "chef/chef-hab"
    +    end
    +
    +    class Inspec
    +      # The InSpec product name
    +      PRODUCT = "Chef InSpec"
    +
    +      # The inspec binary
    +      EXEC = "inspec"
         end
     
         class Org
    @@ -49,7 +82,7 @@
           WEBSITE = "https://chef.io"
     
           # The downloads site
    -      DOWNLOADS_URL = "downloads.chef.io"
    +      DOWNLOADS_URL = "chef.io/downloads"
     
           # The legacy conf folder: C:/opscode/chef. Specifically the "opscode" part
           # DIR_SUFFIX is appended to it in code where relevant
    @@ -63,6 +96,12 @@
     
           # knife documentation page
           KNIFE_DOCS = "https://docs.chef.io/workstation/knife/"
    +
    +      # the name of the overall infra product
    +      PRODUCT = "Chef Infra"
    +
    +      # Omnitruck URL
    +      OMNITRUCK_URL = "https://omnitruck.chef.io/install.sh"
         end
     
         class Server
    @@ -77,6 +116,12 @@
     
           # The server's configuration utility
           SERVER_CTL = "chef-server-ctl"
    +
    +      # The server`s docs URL
    +      SERVER_DOCS = "https://docs.chef.io/server/"
    +
    +      # OS user for server
    +      SYSTEM_USER = "opscode"
         end
     
         class Solo
    @@ -87,6 +132,17 @@
           EXEC = "chef-solo"
         end
     
    +    class Workstation
    +      # The full marketing name of the product
    +      PRODUCT = "Chef Workstation"
    +
    +      # The suffix for Chef Workstation's /opt/chef-workstation or C:\\opscode\chef-workstation
    +      DIR_SUFFIX = "chef-workstation"
    +
    +      # Workstation banner/help text
    +      DOCS = "https://docs.chef.io/workstation/"
    +    end
    +
         class Zero
           # chef-zero executable
           PRODUCT = "Chef Infra Zero"
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/architecture.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/architecture.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/architecture.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/architecture.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/backend.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/backend.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/backend.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/backend.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,27 @@
    +module ChefUtils
    +  module DSL
    +    module Backend
    +      include Internal
    +
    +      # Determine if the backend is local
    +      #
    +      # @param [Chef::Node] node the node to check
    +      #
    +      # @return [Boolean]
    +      #
    +      def local_mode?
    +        node["platform_backend"] == "local"
    +      end
    +
    +      # Determine if the backend is remote
    +      #
    +      # @param [Chef::Node] node the node to check
    +      #
    +      # @return [Boolean]
    +      #
    +      def target_mode?
    +        node["platform_backend"] != "local"
    +      end
    +    end
    +  end
    +end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/cloud.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/cloud.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/cloud.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/cloud.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -23,7 +23,7 @@
         module Cloud
           include Internal
     
    -      # Determine if the current node is "in the cloud".
    +      # Determine if the current node is running in a known cloud.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -35,7 +35,18 @@
             !node["cloud"].nil?
           end
     
    -      # Return true if the current current node is in EC2.
    +      # Determine if the current node is running in Alibaba Cloud
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def alibaba?(node = __getnode)
    +        node.key?("alibaba")
    +      end
    +
    +      # Determine if the current node is running in AWS EC2.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -46,7 +57,7 @@
             node.key?("ec2")
           end
     
    -      # Return true if the current current node is in GCE.
    +      # Determine if the current node running in Google Compute Engine (GCE).
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -57,7 +68,7 @@
             node.key?("gce")
           end
     
    -      # Return true if the current current node is in Rackspace.
    +      # Determine if the current node is running in Rackspace.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -68,7 +79,7 @@
             node.key?("rackspace")
           end
     
    -      # Return true if the current current node is in Eucalyptus.
    +      # Determine if the current node is running in Eucalyptus.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -81,7 +92,7 @@
           # chef-sugar backcompat method
           alias_method :euca?, :eucalyptus?
     
    -      # Return true if the current current node is in Linode.
    +      # Determine if the current node is running in Linode.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -92,7 +103,7 @@
             node.key?("linode")
           end
     
    -      # Return true if the current current node is in OpenStack.
    +      # Determine if the current node is running in OpenStack.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -103,7 +114,7 @@
             node.key?("openstack")
           end
     
    -      # Return true if the current current node is in Azure.
    +      # Determine if the current node is running in Microsoft Azure.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -114,7 +125,7 @@
             node.key?("azure")
           end
     
    -      # Return true if the current current node is in DigitalOcean.
    +      # Determine if the current node is running in DigitalOcean.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -127,7 +138,7 @@
           # chef-sugar backcompat method
           alias_method :digitalocean?, :digital_ocean?
     
    -      # Return true if the current current node is in SoftLayer.
    +      # Determine if the current node is running in SoftLayer (IBM Cloud).
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    @@ -138,6 +149,17 @@
             node.key?("softlayer")
           end
     
    +      # Determine if the current node is running in Oracle Cloud Infrastructure (OCI).
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 19.1
    +      #
    +      # @return [Boolean]
    +      #
    +      def oci?(node = __getnode)
    +        node.key?("oci")
    +      end
    +
           extend self
         end
       end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/default_paths.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/default_paths.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/default_paths.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/default_paths.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/introspection.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/introspection.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/introspection.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/introspection.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -29,6 +29,17 @@
         module Introspection
           include TrainHelpers
     
    +      # Determine if the node is using the Chef Effortless pattern in which the Chef Infra Client is packaged using Chef Habitat
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def effortless?(node = __getnode)
    +        !!(node && node.read("chef_packages", "chef", "chef_effortless"))
    +      end
    +
           # Determine if the node is a docker container.
           #
           # @param [Chef::Node] node the node to check
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/os.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/os.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/os.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/os.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/path_sanity.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/path_sanity.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/path_sanity.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/path_sanity.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_family.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_family.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_family.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_family.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -77,7 +77,7 @@
           # @return [Boolean]
           #
           def macos?(node = __getnode)
    -        node["platform_family"] == "mac_os_x"
    +        node ? node["platform_family"] == "mac_os_x" : macos_ruby?
           end
           # chef-sugar backcompat method
           alias_method :osx?, :macos?
    @@ -86,6 +86,17 @@
           # chef-sugar backcompat method
           alias_method :mac_os_x?, :macos?
     
    +      # Determine if the Ruby VM is currently running on a Mac node (This is useful primarily for internal use
    +      # by Chef Infra Client before the node object exists).
    +      #
    +      # @since 17.3
    +      #
    +      # @return [Boolean]
    +      #
    +      def macos_ruby?
    +        !!(RUBY_PLATFORM =~ /darwin/)
    +      end
    +
           # Determine if the current node is a member of the 'rhel' platform family (Red Hat, CentOS, Oracle or Scientific Linux, but NOT Amazon Linux or Fedora).
           #
           # @param [Chef::Node] node the node to check
    @@ -259,12 +270,17 @@
           # Determine if the Ruby VM is currently running on a Windows node (ChefSpec can never stub
           # this behavior, so this is useful for code which can never be parsed on a non-Windows box).
           #
    +      # April 2022 - Note that we changed the platform identifier from 'mingw32' to 'mingw'
    +      # We did this because Ruby 3.1 introduces the new universal windows platform of 'x64-mingw-ucrt'
    +      # We updated the existing regex snippet to capture both the 32-bit platform and the new x64
    +      # universal platform
    +      #
           # @since 15.5
           #
           # @return [Boolean]
           #
           def windows_ruby?
    -        !!(RUBY_PLATFORM =~ /mswin|mingw32|windows/)
    +        !!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
           end
     
           #
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -123,6 +123,21 @@
           # chef-sugar backcompat method
           alias_method :centos?, :centos_platform?
     
    +      # Determine if the current node is CentOS Stream.
    +      #
    +      # @param [Chef::Node] node the node to check
    +      # @since 17.0
    +      #
    +      # @return [Boolean]
    +      #
    +      def centos_stream_platform?(node = __getnode)
    +        if node["os_release"]
    +          node.dig("os_release", "name") == "CentOS Stream"
    +        else
    +          node.dig("lsb", "id") == "CentOSStream"
    +        end
    +      end
    +
           # Determine if the current node is Oracle Linux.
           #
           # @param [Chef::Node] node the node to check
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_version.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_version.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/platform_version.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/platform_version.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/service.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/service.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/service.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/service.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/train_helpers.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/train_helpers.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/train_helpers.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/train_helpers.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/virtualization.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/virtualization.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/virtualization.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/virtualization.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -140,6 +140,28 @@
             node.dig("virtualization", "system") == "vmware" && node.dig("virtualization", "role") == "host"
           end
     
    +      # Determine if the current node is virtualized on VMware Desktop (Fusion/Player/Workstation).
    +      #
    +      # @param [Chef::Node] node
    +      # @since 17.9
    +      #
    +      # @return [Boolean]
    +      #
    +      def vmware_desktop?(node = __getnode)
    +        node.dig("virtualization", "system") == "vmware" && node.dig("vmware", "host", "type") == "vmware_desktop"
    +      end
    +
    +      # Determine if the current node is virtualized on VMware vSphere (ESX).
    +      #
    +      # @param [Chef::Node] node
    +      # @since 17.9
    +      #
    +      # @return [Boolean]
    +      #
    +      def vmware_vsphere?(node = __getnode)
    +        node.dig("virtualization", "system") == "vmware" && node.dig("vmware", "host", "type") == "vmware_vsphere"
    +      end
    +
           # Determine if the current node is an openvz guest.
           #
           # @param [Chef::Node] node
    @@ -162,6 +184,17 @@
             node.dig("virtualization", "system") == "openvz" && node.dig("virtualization", "role") == "host"
           end
     
    +      # Determine if the current node is running under Microsoft Hyper-v.
    +      #
    +      # @param [Chef::Node] node
    +      # @since 18.5
    +      #
    +      # @return [Boolean]
    +      #
    +      def hyperv?(node = __getnode)
    +        node.dig("virtualization", "system") == "hyperv" && node.dig("virtualization", "role") == "guest"
    +      end
    +
           # Determine if the current node is running under any virtualization environment
           #
           # @param [Chef::Node] node
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/which.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/which.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/which.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/which.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -46,11 +46,12 @@
           #   end
           #
           # @param [Array<String>] list of commands to search for
    +      # @param [String,Array<String>] array of paths to look in first
           # @param [String,Array<String>] array of extra paths to search through
           # @return [String] the first match
           #
    -      def which(*cmds, extra_path: nil, &block)
    -        where(*cmds, extra_path: extra_path, &block).first || false
    +      def which(*cmds, prepend_path: nil, extra_path: nil, &block)
    +        where(*cmds, prepend_path: prepend_path, extra_path: extra_path, &block).first || false
           end
     
           # Lookup all the instances of an an executable that can be found through the systems search PATH.
    @@ -73,12 +74,13 @@
           #   end
           #
           # @param [Array<String>] list of commands to search for
    +      # @param [String,Array<String>] array of paths to look in first
           # @param [String,Array<String>] array of extra paths to search through
           # @return [String] the first match
           #
    -      def where(*cmds, extra_path: nil, &block)
    +      def where(*cmds, prepend_path: nil, extra_path: nil, &block)
             extra_path ||= __extra_path
    -        paths = __env_path.split(File::PATH_SEPARATOR) + Array(extra_path)
    +        paths = Array(prepend_path) + __env_path.split(File::PATH_SEPARATOR) + Array(extra_path)
             paths.uniq!
             exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : []
             exts.unshift("")
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/dsl/windows.rb ruby-chef-utils-19.2.12/lib/chef-utils/dsl/windows.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/dsl/windows.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/dsl/windows.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -58,7 +58,7 @@
             node["kernel"]["product_type"] == "Server"
           end
     
    -      # Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. IE: NT 6.3 is Windows 8.1 and Windows 2012 R2.
    +      # Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. For example NT 6.3 corresponds to Windows 8.1 and Windows 2012 R2.
           #
           # @param [Chef::Node] node the node to check
           # @since 15.8
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/internal.rb ruby-chef-utils-19.2.12/lib/chef-utils/internal.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/internal.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/internal.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -70,7 +70,7 @@
         #
         def __env_path
           if __transport_connection
    -        __transport_connection.run_command("echo $PATH").stdout || ""
    +        __transport_connection.run_command("echo $PATH").stdout.chomp || ""
           else
             ENV["PATH"] || ""
           end
    @@ -84,7 +84,7 @@
         #
         def __transport_connection
           # Software consumers MUST override this method with their own implementation.  The default behavior here is subject to change.
    -      return Chef.run_context.transport_connection if defined?(Chef) && Chef.respond_to?(:run_context) && Chef&.run_context&.transport_connection
    +      return Chef.run_context.transport_connection if defined?(Chef) && Chef.respond_to?(:run_context) && Chef.run_context&.transport_connection
     
           nil
         end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/mash.rb ruby-chef-utils-19.2.12/lib/chef-utils/mash.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/mash.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/mash.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -94,6 +94,10 @@
           end
         end
     
    +    unless method_defined?(:regular_reader)
    +      alias_method :regular_reader, :[]
    +    end
    +
         unless method_defined?(:regular_writer)
           alias_method :regular_writer, :[]=
         end
    @@ -102,6 +106,19 @@
           alias_method :regular_update, :update
         end
     
    +    unless method_defined?(:regular_clear)
    +      alias_method :regular_clear, :clear
    +    end
    +
    +    unless method_defined?(:regular_delete)
    +      alias_method :regular_delete, :delete
    +    end
    +
    +    # @param key<Object> The key to get.
    +    def [](key)
    +      regular_reader(key)
    +    end
    +
         # @param key<Object> The key to set.
         # @param value<Object>
         #   The value to set the key to.
    @@ -113,6 +130,12 @@
         end
     
         # internal API for use by Chef's deep merge cache
    +    # @api private
    +    def internal_get(key)
    +      regular_reader(key)
    +    end
    +
    +    # internal API for use by Chef's deep merge cache
         # @api private
         def internal_set(key, value)
           regular_writer(key, convert_value(value))
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/parallel_map.rb ruby-chef-utils-19.2.12/lib/chef-utils/parallel_map.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/parallel_map.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/parallel_map.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,131 @@
    +# frozen_string_literal: true
    +#
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
    +# License:: Apache License, Version 2.0
    +#
    +# Licensed under the Apache License, Version 2.0 (the "License");
    +# you may not use this file except in compliance with the License.
    +# You may obtain a copy of the License at
    +#
    +#     http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing, software
    +# distributed under the License is distributed on an "AS IS" BASIS,
    +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +# See the License for the specific language governing permissions and
    +# limitations under the License.
    +#
    +
    +require "concurrent/executors"
    +require "concurrent/future"
    +require "singleton" unless defined?(Singleton)
    +
    +module ChefUtils
    +  #
    +  # This module contains ruby refinements that adds several methods to the Enumerable
    +  # class which are useful for parallel processing.
    +  #
    +  module ParallelMap
    +    refine Enumerable do
    +
    +      # Enumerates through the collection in parallel using the thread pool provided
    +      # or the default thread pool.  By using the default thread pool this supports
    +      # recursively calling the method without deadlocking while using a globally
    +      # fixed number of workers.  This method supports lazy collections.  It returns
    +      # synchronously, waiting until all the work is done.  Failures are only reported
    +      # after the collection has executed and only the first exception is raised.
    +      #
    +      # (0..).lazy.parallel_map { |i| i*i }.first(5)
    +      #
    +      # @return [Array] output results
    +      #
    +      def parallel_map(pool: nil)
    +        return self unless block_given?
    +
    +        pool ||= ChefUtils::DefaultThreadPool.instance.pool
    +
    +        futures = map do |item|
    +          Concurrent::Future.execute(executor: pool) do
    +            yield item
    +          end
    +        end
    +
    +        futures.map(&:value!)
    +      end
    +
    +      # This has the same behavior as parallel_map but returns the enumerator instead of
    +      # the return values.
    +      #
    +      # @return [Enumerable] the enumerable for method chaining
    +      #
    +      def parallel_each(pool: nil, &block)
    +        return self unless block_given?
    +
    +        parallel_map(pool: pool, &block)
    +
    +        self
    +      end
    +
    +      # The flat_each method is tightly coupled to the usage of parallel_map within the
    +      # ChefFS implementation.  It is not itself a parallel method, but it is used to
    +      # iterate through the 2nd level of nested structure, which is tied to the nested
    +      # structures that ChefFS returns.
    +      #
    +      # This is different from Enumerable#flat_map because that behaves like map.flatten(1) while
    +      # this behaves more like flatten(1).each.  We need this on an Enumerable, so we have no
    +      # Enumerable#flatten method to call.
    +      #
    +      # [ [ 1, 2 ], [ 3, 4 ] ].flat_each(&block) calls block four times with 1, 2, 3, 4
    +      #
    +      # [ [ 1, 2 ], [ 3, 4 ] ].flat_map(&block) calls block twice with [1, 2] and [3,4]
    +      #
    +      def flat_each(&block)
    +        map do |value|
    +          if value.is_a?(Enumerable)
    +            value.each(&block)
    +          else
    +            yield value
    +          end
    +        end
    +      end
    +    end
    +  end
    +
    +  # The DefaultThreadPool has a fixed thread size and has no
    +  # queue of work and the behavior on failure to find a thread is for the
    +  # caller to run the work.  This contract means that the thread pool can
    +  # be called recursively without deadlocking and while keeping the fixed
    +  # number of threads (and not exponentially growing the thread pool with
    +  # the depth of recursion).
    +  #
    +  class DefaultThreadPool
    +    include Singleton
    +
    +    DEFAULT_THREAD_SIZE = 10
    +
    +    # Size of the thread pool, must be set before getting the thread pool or
    +    # calling parallel_map/parallel_each.  Does not (but could be modified to)
    +    # support dynamic resizing. To get fully synchronous behavior set this equal to
    +    # zero rather than one since the caller will get work if the threads are
    +    # busy.
    +    #
    +    # @return [Integer] number of threads
    +    attr_accessor :threads
    +
    +    # Memoizing accessor for the thread pool
    +    #
    +    # @return [Concurrent::ThreadPoolExecutor] the thread pool
    +    def pool
    +      @pool ||= Concurrent::ThreadPoolExecutor.new(
    +        min_threads: threads || DEFAULT_THREAD_SIZE,
    +        max_threads: threads || DEFAULT_THREAD_SIZE,
    +        max_queue: 0,
    +        # "synchronous" redefines the 0 in max_queue to mean 'no queue' instead of 'infinite queue'
    +        # it does not mean synchronous execution (no threads) but synchronous offload to the threads.
    +        synchronous: true,
    +        # this prevents deadlocks on recursive parallel usage
    +        fallback_policy: :caller_runs
    +      )
    +    end
    +  end
    +end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils/version.rb ruby-chef-utils-19.2.12/lib/chef-utils/version.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils/version.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils/version.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,5 +1,5 @@
     # frozen_string_literal: true
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -16,5 +16,5 @@
     
     module ChefUtils
       CHEFUTILS_ROOT = File.expand_path("..", __dir__)
    -  VERSION = "16.12.3"
    +  VERSION = "19.2.12"
     end
    diff -Nru ruby-chef-utils-16.12.3/lib/chef-utils.rb ruby-chef-utils-19.2.12/lib/chef-utils.rb
    --- ruby-chef-utils-16.12.3/lib/chef-utils.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/lib/chef-utils.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,6 +17,7 @@
     #
     
     require_relative "chef-utils/dsl/architecture"
    +require_relative "chef-utils/dsl/backend"
     require_relative "chef-utils/dsl/cloud"
     require_relative "chef-utils/dsl/introspection"
     require_relative "chef-utils/dsl/os"
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/architecture_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/architecture_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/architecture_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/architecture_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/cloud_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/cloud_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/cloud_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/cloud_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,7 +17,6 @@
     #
     
     require "spec_helper"
    -require "fauxhai"
     
     def cloud_reports_true_for(*args, node:)
       args.each do |method|
    @@ -45,6 +44,10 @@
         end
       end
     
    +  context "on alibaba" do
    +    cloud_reports_true_for(:cloud?, :alibaba?, node: { "alibaba" => {}, "cloud" => {} })
    +  end
    +
       context "on ec2" do
         cloud_reports_true_for(:cloud?, :ec2?, node: { "ec2" => {}, "cloud" => {} })
       end
    @@ -81,6 +84,10 @@
         cloud_reports_true_for(:cloud?, :softlayer?, node: { "softlayer" => {}, "cloud" => {} })
       end
     
    +  context "on oci" do
    +    cloud_reports_true_for(:cloud?, :oci?, node: { "oci" => {}, "cloud" => {} })
    +  end
    +
       context "on virtualbox" do
         it "does not return true for cloud?" do
           expect(described_class.cloud?({ "virtualbox" => {}, "cloud" => nil })).to be false
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/dsl_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/dsl_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/dsl_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/dsl_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/introspection_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/introspection_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/introspection_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/introspection_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -32,6 +32,18 @@
     
       let(:test_instance) { IntrospectionTestClass.new(node) }
     
    +  context "#effortless?" do
    +    # FIXME: use a real VividMash for these tests instead of stubbing
    +    it "is false by default" do
    +      expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(nil)
    +      expect(ChefUtils.effortless?(node)).to be false
    +    end
    +    it "is true when ohai reports a effortless" do
    +      expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(true)
    +      expect(ChefUtils.effortless?(node)).to be true
    +    end
    +  end
    +
       context "#docker?" do
         # FIXME: use a real VividMash for these tests instead of stubbing
         it "is false by default" do
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/os_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/os_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/os_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/os_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/path_sanity_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/path_sanity_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/path_sanity_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/path_sanity_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -79,7 +79,7 @@
         end
     
         it "prepends to an existing path" do
    -      env = { "PATH" => '%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\\' }
    +      env = { "PATH" => "%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\" }
           expect(test_instance.default_paths(env)).to eql("#{Gem.bindir};#{RbConfig::CONFIG["bindir"]};%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\")
         end
       end
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/platform_family_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/platform_family_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/platform_family_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/platform_family_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -25,7 +25,7 @@
           expect(described_class.send(method, node)).to be true
         end
       end
    -  (PLATFORM_FAMILY_HELPERS - [ :windows_ruby? ] - args).each do |method|
    +  (PLATFORM_FAMILY_HELPERS - %i{windows_ruby? macos_ruby?} - args).each do |method|
         it "reports false for #{method}" do
           expect(described_class.send(method, node)).to be false
         end
    @@ -41,7 +41,7 @@
         end
       end
     
    -  ( PLATFORM_FAMILY_HELPERS - [ :windows_ruby? ]).each do |helper|
    +  ( PLATFORM_FAMILY_HELPERS - %i{windows_ruby? macos_ruby?}).each do |helper|
         it "has the #{helper} in the ChefUtils module" do
           expect(ChefUtils).to respond_to(helper)
         end
    @@ -90,13 +90,13 @@
       end
     
       context "on centos6" do
    -    let(:options) { { platform: "centos", version: "6.10" } }
    +    let(:options) { { platform: "centos", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on centos7" do
    -    let(:options) { { platform: "centos", version: "7.7.1908" } }
    +    let(:options) { { platform: "centos", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -108,7 +108,7 @@
       end
     
       context "on clearos7" do
    -    let(:options) { { platform: "clearos", version: "7.4" } }
    +    let(:options) { { platform: "clearos", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -156,25 +156,25 @@
       end
     
       context "on oracle6" do
    -    let(:options) { { platform: "oracle", version: "6.10" } }
    +    let(:options) { { platform: "oracle", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on oracle7" do
    -    let(:options) { { platform: "oracle", version: "7.6" } }
    +    let(:options) { { platform: "oracle", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
     
       context "on redhat6" do
    -    let(:options) { { platform: "redhat", version: "6.10" } }
    +    let(:options) { { platform: "redhat", version: "6" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
       end
     
       context "on redhat7" do
    -    let(:options) { { platform: "redhat", version: "7.6" } }
    +    let(:options) { { platform: "redhat", version: "7" } }
     
         pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
       end
    @@ -210,7 +210,7 @@
       end
     
       context "node-independent windows APIs" do
    -    if RUBY_PLATFORM.match?(/mswin|mingw32|windows/)
    +    if RUBY_PLATFORM.match?(/mswin|mingw|windows/)
           it "reports true for :windows_ruby?" do
             expect(described_class.windows_ruby?).to be true
           end
    @@ -220,4 +220,16 @@
           end
         end
       end
    +
    +  context "node-independent mac APIs" do
    +    if RUBY_PLATFORM.match?(/darwin/)
    +      it "reports true for :macos_ruby?" do
    +        expect(described_class.macos_ruby?).to be true
    +      end
    +    else
    +      it "reports false for :macos_ruby?" do
    +        expect(described_class.macos_ruby?).to be false
    +      end
    +    end
    +  end
     end
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/platform_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/platform_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/platform_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/platform_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -145,6 +145,20 @@
         platform_reports_true_for(:centos?, :centos_platform?)
       end
     
    +  context "on centos stream w/o os_release" do
    +    let(:options) { { platform: "centos" } }
    +    let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "lsb" => { "id" => "CentOSStream" }, "os_release" => nil } }
    +
    +    platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
    +  end
    +
    +  context "on centos stream w/ os_release" do
    +    let(:options) { { platform: "centos" } }
    +    let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "os_release" => { "name" => "CentOS Stream" } } }
    +
    +    platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
    +  end
    +
       context "on clearos" do
         let(:options) { { platform: "clearos" } }
     
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/service_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/service_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/service_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/service_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/virtualization_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/virtualization_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/virtualization_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/virtualization_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    @@ -17,7 +17,6 @@
     #
     
     require "spec_helper"
    -require "fauxhai"
     
     def virtualization_reports_true_for(*args, node:)
       args.each do |method|
    @@ -45,6 +44,9 @@
         end
       end
     
    +  context "on hyperv" do
    +    virtualization_reports_true_for(:guest?, :virtual?, :hyperv?, node: { "virtualization" => { "system" => "hyperv", "role" => "guest" } })
    +  end
       context "on kvm" do
         virtualization_reports_true_for(:guest?, :virtual?, :kvm?, node: { "virtualization" => { "system" => "kvm",  "role" => "guest" } })
         virtualization_reports_true_for(:hypervisor?, :physical?, :kvm_host?, node: { "virtualization" => { "system" => "kvm", "role" => "host" } })
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/which_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/which_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/which_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/which_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/dsl/windows_spec.rb ruby-chef-utils-19.2.12/spec/unit/dsl/windows_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/dsl/windows_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/dsl/windows_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,6 +1,6 @@
     # frozen_string_literal: true
     #
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/mash_spec.rb ruby-chef-utils-19.2.12/spec/unit/mash_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/mash_spec.rb	2021-04-09 10:56:49.000000000 +0200
    +++ ruby-chef-utils-19.2.12/spec/unit/mash_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -1,7 +1,7 @@
     # frozen_string_literal: true
     #
     # Author:: Matthew Kent (<mkent@magoazul.com>)
    -# Copyright:: Copyright (c) Chef Software Inc.
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
     # License:: Apache License, Version 2.0
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
    diff -Nru ruby-chef-utils-16.12.3/spec/unit/parallel_map_spec.rb ruby-chef-utils-19.2.12/spec/unit/parallel_map_spec.rb
    --- ruby-chef-utils-16.12.3/spec/unit/parallel_map_spec.rb	1970-01-01 01:00:00.000000000 +0100
    +++ ruby-chef-utils-19.2.12/spec/unit/parallel_map_spec.rb	2026-06-03 12:04:51.000000000 +0200
    @@ -0,0 +1,156 @@
    +# frozen_string_literal: true
    +#
    +# Copyright:: Copyright (c) 2009-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
    +# License:: Apache License, Version 2.0
    +#
    +# Licensed under the Apache License, Version 2.0 (the "License");
    +# you may not use this file except in compliance with the License.
    +# You may obtain a copy of the License at
    +#
    +#     http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing, software
    +# distributed under the License is distributed on an "AS IS" BASIS,
    +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +# See the License for the specific language governing permissions and
    +# limitations under the License.
    +#
    +
    +require "chef-utils/parallel_map"
    +
    +using ChefUtils::ParallelMap
    +
    +RSpec.describe ChefUtils::ParallelMap do
    +
    +  shared_examples_for "common parallel API tests" do
    +
    +    before(:each) do
    +      ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
    +      ChefUtils::DefaultThreadPool.instance.threads = threads
    +    end
    +
    +    after(:each) do
    +      ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
    +    end
    +
    +    it "parallel_map runs in parallel" do
    +      # this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
    +      val = threads + 1
    +      ret = []
    +      start = Time.now
    +      (1..val).parallel_map do |i|
    +        loop do
    +          if val == i
    +            ret << i
    +            val -= 1
    +            break
    +          end
    +          # we spin for quite awhile to wait for very slow testers if we have to
    +          if Time.now - start > 30
    +            raise "timed out; deadlocked due to lack of parallelization?"
    +          end
    +
    +          # need to sleep a tiny bit to let other threads schedule
    +          sleep 0.000001
    +        end
    +      end
    +      expected = (1..threads + 1).to_a.reverse
    +      expect(ret).to eql(expected)
    +    end
    +
    +    it "parallel_each runs in parallel" do
    +      # this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
    +      val = threads + 1
    +      ret = []
    +      start = Time.now
    +      (1..val).parallel_each do |i|
    +        loop do
    +          if val == i
    +            ret << i
    +            val -= 1
    +            break
    +          end
    +          # we spin for quite awhile to wait for very slow testers if we have to
    +          if Time.now - start > 30
    +            raise "timed out; deadlocked due to lack of parallelization?"
    +          end
    +
    +          # need to sleep a tiny bit to let other threads schedule
    +          sleep 0.000001
    +        end
    +      end
    +      expected = (1..threads + 1).to_a.reverse
    +      expect(ret).to eql(expected)
    +    end
    +
    +    it "parallel_map throws exceptions" do
    +      expect { (0..10).parallel_map { |i| raise "boom" } }.to raise_error(RuntimeError)
    +    end
    +
    +    it "parallel_each throws exceptions" do
    +      expect { (0..10).parallel_each { |i| raise "boom" } }.to raise_error(RuntimeError)
    +    end
    +
    +    it "parallel_map runs" do
    +      ans = Timeout.timeout(30) do
    +        (1..10).parallel_map { |i| i }
    +      end
    +      expect(ans).to eql((1..10).to_a)
    +    end
    +
    +    it "parallel_each runs" do
    +      Timeout.timeout(30) do
    +        (1..10).parallel_each { |i| i }
    +      end
    +    end
    +
    +    it "recursive parallel_map will not deadlock" do
    +      ans = Timeout.timeout(30) do
    +        (1..2).parallel_map { |i| (1..2).parallel_map { |i| i } }
    +      end
    +      expect(ans).to eql([[1, 2], [1, 2]])
    +    end
    +
    +    it "recursive parallel_each will not deadlock" do
    +      Timeout.timeout(30) do
    +        (1..2).parallel_each { |i| (1..2).parallel_each { |i| i } }
    +      end
    +    end
    +
    +    it "parallel_map is lazy" do
    +      ans = Timeout.timeout(30) do
    +        (1..).lazy.parallel_map { |i| i }.first(5)
    +      end
    +      expect(ans).to eql((1..5).to_a)
    +    end
    +
    +    it "parallel_each is lazy" do
    +      Timeout.timeout(30) do
    +        (1..).lazy.parallel_each { |i| i }.first(5)
    +      end
    +    end
    +  end
    +
    +  context "with 10 threads" do
    +    let(:threads) { 10 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "with 0 threads" do
    +    let(:threads) { 0 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "with 1 threads" do
    +    let(:threads) { 1 }
    +    it_behaves_like "common parallel API tests"
    +  end
    +
    +  context "flat_each" do
    +    it "runs each over items which are nested one level" do
    +      sum = 0
    +      [ [ 1, 2 ], [3, 4]].flat_each { |i| sum += i }
    +      expect(sum).to eql(10)
    +    end
    +  end
    +end
    Norwid Behrnd at June 11, 2026, 9:42 a.m.

Upload #4

Information

Version: 19.2.12-0.1
Uploaded: 2026-04-20 14:36
Source package: ruby-chef-utils_19.2.12-0.1.dsc
Distribution: unstable
Section: ruby
Priority:
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467 #1127665

Changelog

 ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
 .
   * NMU upload.
 .
   [ Lucas Nussbaum ]
   * debian/gbp.conf: Add for DEP-14
   * debian/salsa-ci.yml: use team-specific include
 .
   [ Norwid Behrnd ]
   * fix: reactivate watch file (Closes: #1127665)
   * New upstream version 19.2.12
   * fix: amend ruby-concurrent as dependency (Closes: #1123467)
   * update to Debian policy 4.7.4
   * update debian/watch to version 5
   * amend debian/copyright (upstream contact)

QA information

Comments

  1. Dear reviewing sponsor
    
    The corresponding public repository of this upload is <https://salsa.debian.org/nbehrnd/p06_f>.  If accepted, I intend to file changes there up and including commit `7f256476` as a pull request to the blessed repository of `ruby-chef-utils` at <https://salsa.debian.org/ruby-team/ruby-chef-utils> _instead_ my two earlier filed PRs filed on February 11, 2026.
    
    I am no longer able to continue work in previously used <https://salsa.debian.org/nbehrnd/p06> which once successfully run `debian/salsa-ci.yml` and badge.  See, for instance, pipeline <https://salsa.debian.org/nbehrnd/p06/-/pipelines/1069482> by yesterday April 19, 2026 at 11:15:21 GMT+2 which passes, while pipeline <https://salsa.debian.org/nbehrnd/p06/-/pipelines/1070119> run today April 20, 2026 at 11:07:19 GMT+2 does not.  Which is why I started all over again.
    Ready Norwid Behrnd at April 20, 2026, 2:58 p.m.
  2. Today, I added an empty commit (56c54440) to the deposit on salsa.debian.org.  This allowed to launch `debian/salsa-ci.yml`, each checked passed.
    Ready Norwid Behrnd at April 23, 2026, 1:01 p.m.

Upload #3

Information

Version: 19.2.12-0.1
Uploaded: 2026-04-19 09:36
Source package: ruby-chef-utils_19.2.12-0.1.dsc
Distribution: unstable
Section: ruby
Priority:
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467 #1127665

Changelog

 ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
 .
   * NMU upload.
 .
   [ Lucas Nussbaum ]
   * debian/gbp.conf: Add for DEP-14
   * debian/salsa-ci.yml: use team-specific include
 .
   [ Norwid Behrnd ]
   * fix: reactivate debian/watch (Closes: #1127665)
   * New upstream version 19.2.12
   * fix: add ruby-concurrent as dependency (Closes: #1123467)
   * update to Debian policy 4.7.4
   * update debian/watch to version 5

QA information

Comments

No comments

Upload #2

Information

Version: 19.2.12-0.1
Uploaded: 2026-04-17 15:36
Source package: ruby-chef-utils_19.2.12-0.1.dsc
Distribution: unstable
Section: ruby
Priority:
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467 #1127665

Changelog

 ruby-chef-utils (19.2.12-0.1) unstable; urgency=medium
 .
   * NMU upload.
 .
   [ Lucas Nussbaum ]
   * debian/gbp.conf: Add for DEP-14
   * debian/salsa-ci.yml: use team-specific include
 .
   [ Norwid Behrnd ]
   * fix: reactivate debian/watch (Closes: #1127665)
   * New upstream version 19.2.12
   * fix: add ruby-concurrent as dependency (Closes: #1123467)
   * update to Debian policy 4.7.3
   * update debian/watch to version 5

QA information

Comments

  1. This upload to prepare a NMU is build from <https://salsa.debian.org/nbehrnd/p06>, commit d8b6bbc5.  It is preliminary as the information about an upstream-contact (file debian/copyright) is still missing.  The issue was addressed in a question to chef's mailing list, https://discourse.chef.io/t/chef-utils-who-serves-as-upstream-contact-for-the-debian-package/24645
    Needs work Norwid Behrnd at April 17, 2026, 4:01 p.m.

Upload #1

Information

Version: 19.1.164-1.1
Uploaded: 2026-03-12 19:43
Source package: ruby-chef-utils_19.1.164-1.1.dsc
Distribution: unstable
Section: ruby
Priority:
Homepage: https://github.com/chef/chef/tree/master/chef-utils
Vcs-Git: https://salsa.debian.org/ruby-team/ruby-chef-utils.git
Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-chef-utils
Closes bugs: #1123467

Changelog

 ruby-chef-utils (19.1.164-1.1) unstable; urgency=medium
 .
   * Non-maintainer upload
 .
   [ Lucas Nussbaum ]
   * debian/gbp.conf: Add for DEP-14
   * debian/salsa-ci.yml: use team-specific include
 .
   [ Norwid Behrnd ]
   * New upstream version 19.1.164
   * Reuse d/watch (stays at version 4)
   * Change to standards version 4.7.3
   * Closes: #1123467

QA information

Comments

  1. The upload serves as a basis for discussion with the package's maintainer, the Ruby Debian Team.  While its state is not yet "good enough" to file a RFS, I see the mentors page as way to document and share the state achivied.
    Needs work Norwid Behrnd at March 12, 2026, 9:11 p.m.