From a6cec880ee5f57a4433d4c764946a94ae900293e Mon Sep 17 00:00:00 2001 From: Christopher Thorn Date: Mon, 26 Oct 2026 18:52:28 -0700 Subject: [PATCH 1/3] (PA-9451) Add opt-in Puppet 9 / Ruby 4 support to shared workflows Add a puppet_versions input (JSON list, default '["8"]') to the nightly and released unit test workflows. Puppet 8 continues to run on Ruby 3.1; later versions run on Ruby 4.0. Defaulting to Puppet 8 keeps existing callers' jobs and check names unchanged, unlike the earlier attempt that added Puppet 9 to every caller and broke modules still pinned to puppetlabs_spec_helper 8. For Puppet 9+ nightly on Windows, use the published x64-mingw-ucrt gem instead of the universal gem plus pinned ffi workaround. Add a ruby_version input (default '3.3') to the static code analysis workflow. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/static_code_analysis.yaml | 10 ++++-- .../unit_tests_with_nightly_puppet_gem.yaml | 35 +++++++++++-------- .../unit_tests_with_released_puppet_gem.yaml | 19 ++++++---- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/.github/workflows/static_code_analysis.yaml b/.github/workflows/static_code_analysis.yaml index 26170b8..40d3313 100644 --- a/.github/workflows/static_code_analysis.yaml +++ b/.github/workflows/static_code_analysis.yaml @@ -1,14 +1,20 @@ --- name: Static Code Analysis -on: workflow_call +on: + workflow_call: + inputs: + ruby_version: + description: 'Ruby version to run the checks with' + type: string + default: '3.3' jobs: static_code_analysis: name: Run checks env: - ruby_version: '3.3' + ruby_version: ${{ inputs.ruby_version }} extra_checks: check:symlinks check:git_ignore check:dot_underscore check:test_file PUPPET_FORGE_TOKEN: 'YES' diff --git a/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml b/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml index d262fcc..bff89de 100644 --- a/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml +++ b/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml @@ -1,19 +1,25 @@ --- name: Unit Tests with nightly Puppet gem -on: workflow_call +on: + workflow_call: + inputs: + puppet_versions: + description: 'JSON list of Puppet major versions to test, e.g. ''["8", "9"]''. Puppet 8 runs on Ruby 3.1; later versions run on Ruby 4.0.' + type: string + default: '["8"]' jobs: unit_tests_with_nightly_puppet_gem: - name: Puppet${{ matrix.puppet_version }} gem on Ruby ${{ matrix.ruby }} on ${{ matrix.os_type }} + name: Puppet${{ matrix.puppet_version }} gem on Ruby ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} on ${{ matrix.os_type }} strategy: matrix: os: ['ubuntu-latest', 'windows-2022'] - puppet_version: ['8'] + puppet_version: ${{ fromJSON(inputs.puppet_versions) }} + # The Ruby version is derived from puppet_version in expressions below + # rather than via include entries, because an include entry for a + # puppet_version that the caller didn't request creates a stray job. include: - - puppet_version: '8' - ruby: '3.1' - - os: 'ubuntu-latest' os_type: 'Linux' env_set_cmd: 'export ' @@ -26,10 +32,11 @@ jobs: - os: 'windows-2022' os_type: 'Windows' env_set_cmd: '$env:' - # setup-ruby uses ucrt for newer Rubies, but we only support mingw - # in our Windows Puppet nightly gems. For now, we'll just install - # the universal gem and manually install the ffi dependency. - # Use the latest known good version of the ffi gem. + # setup-ruby uses ucrt for newer Rubies, but Puppet 8 nightly gems + # are only published for mingw. For Puppet 8, install the + # universal gem and manually install the ffi dependency, using the + # latest known good version of ffi. Puppet 9 and later publish an + # x64-mingw-ucrt gem, which is used instead (see the install step). gem_file: 'puppet-latest.gem' extra_steps: 'gem install ffi --version 1.16.3' @@ -42,15 +49,15 @@ jobs: - name: Checkout current PR code uses: actions/checkout@v6 - - name: Install ruby version ${{ matrix.ruby }} + - name: Install ruby version ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} uses: ruby/setup-ruby@v1 with: - ruby-version: ${{ matrix.ruby }} + ruby-version: ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} - name: Install the latest nightly build of puppet${{ matrix.puppet_version }} gem run: | - ${{ matrix.extra_steps }} - curl https://artifactory.delivery.puppetlabs.net/artifactory/internal_nightly__local/downloads/gems/puppet${{ matrix.puppet_version }}-nightly/${{ matrix.gem_file }} --output puppet.gem --location + ${{ matrix.puppet_version == '8' && matrix.extra_steps || '' }} + curl https://artifactory.delivery.puppetlabs.net/artifactory/internal_nightly__local/downloads/gems/puppet${{ matrix.puppet_version }}-nightly/${{ (matrix.os_type == 'Windows' && matrix.puppet_version != '8') && 'puppet-latest-x64-mingw-ucrt.gem' || matrix.gem_file }} --output puppet.gem --location gem sources --add https://artifactory.delivery.puppetlabs.net/artifactory/api/gems/rubygems/ gem sources --remove https://rubygems.org/ gem install puppet.gem -N diff --git a/.github/workflows/unit_tests_with_released_puppet_gem.yaml b/.github/workflows/unit_tests_with_released_puppet_gem.yaml index 60e98bf..9a67c72 100644 --- a/.github/workflows/unit_tests_with_released_puppet_gem.yaml +++ b/.github/workflows/unit_tests_with_released_puppet_gem.yaml @@ -3,21 +3,26 @@ name: Unit Tests with released Puppet gem on: workflow_call: + inputs: + puppet_versions: + description: 'JSON list of Puppet major versions to test, e.g. ''["8", "9"]''. Puppet 8 runs on Ruby 3.1; later versions run on Ruby 4.0.' + type: string + default: '["8"]' secrets: PUPPET_FORGE_TOKEN_PUBLIC: required: true jobs: unit_tests_with_released_puppet_gem: - name: Puppet${{ matrix.puppet_version }} gem on Ruby ${{ matrix.ruby }} on ${{ matrix.os_type }} + name: Puppet${{ matrix.puppet_version }} gem on Ruby ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} on ${{ matrix.os_type }} strategy: matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-2022'] - puppet_version: ['8'] + puppet_version: ${{ fromJSON(inputs.puppet_versions) }} + # The Ruby version is derived from puppet_version in expressions below + # rather than via include entries, because an include entry for a + # puppet_version that the caller didn't request creates a stray job. include: - - puppet_version: '8' - ruby: '3.1' - - os: 'ubuntu-latest' os_type: 'Linux' - os: 'macos-latest' @@ -30,10 +35,10 @@ jobs: - name: Checkout current PR code uses: actions/checkout@v6 - - name: Install ruby version ${{ matrix.ruby }} + - name: Install ruby version ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} uses: ruby/setup-ruby@v1 with: - ruby-version: ${{ matrix.ruby }} + ruby-version: ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} bundler-cache: true env: BUNDLE_RUBYGEMS___PUPPETCORE__PUPPET__COM: forge-key:${{ secrets.PUPPET_FORGE_TOKEN_PUBLIC || '' }} From 36eaf7bcf4860757a190e1ed1b7c3d9650e2f120 Mon Sep 17 00:00:00 2001 From: Christopher Thorn Date: Mon, 26 Oct 2026 20:04:53 -0700 Subject: [PATCH 2/3] (PA-9451) Fix Ruby 4 bundle failures in unit test workflows Install libcurl development files on Linux for Puppet 9+. Under Ruby 4, Bundler can resolve a faraday version that depends on patron, whose native extension needs them. static_code_analysis.yaml already does this. In the nightly workflow, GEM_SOURCE was only set for the bundler step. The Gemfile uses it as its source, so `bundle exec` in the test step saw a different source than `bundle update` resolved against and re-resolved. Under the Bundler shipped with Ruby 4, that re-resolution fails with a lockfile platform error. Set GEM_SOURCE for the whole job. Move PUPPET_GEM_VERSION to the job as well, for consistency and to drop the per-OS env_set_cmd syntax. This applies to Puppet 8 nightly jobs too: their test step now sees the same GEM_SOURCE and PUPPET_GEM_VERSION as their bundler step. Co-Authored-By: Claude Opus 5.5 --- .../unit_tests_with_nightly_puppet_gem.yaml | 21 +++++++++++++------ .../unit_tests_with_released_puppet_gem.yaml | 9 ++++++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml b/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml index bff89de..fe8f9d0 100644 --- a/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml +++ b/.github/workflows/unit_tests_with_nightly_puppet_gem.yaml @@ -22,16 +22,13 @@ jobs: include: - os: 'ubuntu-latest' os_type: 'Linux' - env_set_cmd: 'export ' gem_file: 'puppet-latest.gem' # macos is not yet supported by twingate, see https://github.com/Twingate/github-action/issues/43 # - os: 'macos-latest' # os_type: 'macOS' - # env_set_cmd: 'export ' # gem_file: 'puppet-latest-universal-darwin.gem' - os: 'windows-2022' os_type: 'Windows' - env_set_cmd: '$env:' # setup-ruby uses ucrt for newer Rubies, but Puppet 8 nightly gems # are only published for mingw. For Puppet 8, install the # universal gem and manually install the ffi dependency, using the @@ -41,6 +38,12 @@ jobs: extra_steps: 'gem install ffi --version 1.16.3' runs-on: ${{ matrix.os }} + # Set for the whole job so that `bundle exec` in the test step evaluates + # the Gemfile the same way `bundle update` did. Otherwise Bundler + # re-resolves, which fails under the Bundler shipped with Ruby 4. + env: + GEM_SOURCE: "https://artifactory.delivery.puppetlabs.net/artifactory/api/gems/rubygems/" + PUPPET_GEM_VERSION: "file://puppet_gem_extracted" steps: - name: Install twingate uses: twingate/github-action@v1 @@ -49,6 +52,15 @@ jobs: - name: Checkout current PR code uses: actions/checkout@v6 + # Patron, a transitive dependency of beaker-abs, requires cURL + # libraries. Under Ruby 4, Bundler can resolve a faraday version that + # pulls it in, so install them for Puppet 9 and later. + - name: Install cURL development files + if: runner.os == 'Linux' && matrix.puppet_version != '8' + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev + - name: Install ruby version ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} uses: ruby/setup-ruby@v1 with: @@ -64,13 +76,10 @@ jobs: ruby -e "require 'rubygems/package'; require 'fileutils'; pkg = Gem::Package.new('puppet.gem'); spec = pkg.spec; dir = 'puppet_gem_extracted'; FileUtils.mkdir_p(dir); pkg.extract_files(dir); File.write(File.join(dir, spec.name + '.gemspec'), spec.to_ruby)" - name: Prepare testing environment with bundler - env: - GEM_SOURCE: "https://artifactory.delivery.puppetlabs.net/artifactory/api/gems/rubygems/" run: | git config --global core.longpaths true bundle config set system 'true' bundle config set --local without 'release' - ${{ matrix.env_set_cmd }}PUPPET_GEM_VERSION="file://puppet_gem_extracted" bundle update --jobs 4 --retry 3 - name: Run unit tests diff --git a/.github/workflows/unit_tests_with_released_puppet_gem.yaml b/.github/workflows/unit_tests_with_released_puppet_gem.yaml index 9a67c72..534c10e 100644 --- a/.github/workflows/unit_tests_with_released_puppet_gem.yaml +++ b/.github/workflows/unit_tests_with_released_puppet_gem.yaml @@ -35,6 +35,15 @@ jobs: - name: Checkout current PR code uses: actions/checkout@v6 + # Patron, a transitive dependency of beaker-abs, requires cURL + # libraries. Under Ruby 4, Bundler can resolve a faraday version that + # pulls it in, so install them for Puppet 9 and later. + - name: Install cURL development files + if: runner.os == 'Linux' && matrix.puppet_version != '8' + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev + - name: Install ruby version ${{ matrix.puppet_version == '8' && '3.1' || '4.0' }} uses: ruby/setup-ruby@v1 with: From 119b4f941b725337b94151d1e77f6a12930f3799 Mon Sep 17 00:00:00 2001 From: Christopher Thorn Date: Mon, 26 Oct 2026 19:53:00 -0700 Subject: [PATCH 3/3] (PA-9451) Pin Puppet major version in released unit test workflow Set PUPPET_GEM_VERSION to "~> .0" for each job. Without it, a dependency conflict on Windows made Bundler silently resolve Puppet 8 in the Puppet 9 job. Puppet 8 jobs already resolve 8.x on Ruby 3.1, so this doesn't change existing callers. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/unit_tests_with_released_puppet_gem.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/unit_tests_with_released_puppet_gem.yaml b/.github/workflows/unit_tests_with_released_puppet_gem.yaml index 534c10e..c9d14fe 100644 --- a/.github/workflows/unit_tests_with_released_puppet_gem.yaml +++ b/.github/workflows/unit_tests_with_released_puppet_gem.yaml @@ -31,6 +31,10 @@ jobs: os_type: 'Windows' runs-on: ${{ matrix.os }} + # Pin the Puppet major version so that a dependency conflict fails the + # job instead of Bundler silently resolving an older Puppet. + env: + PUPPET_GEM_VERSION: "~> ${{ matrix.puppet_version }}.0" steps: - name: Checkout current PR code uses: actions/checkout@v6