diff --git a/.github/workflows/test-migration.yaml b/.github/workflows/test-migration.yaml index 59633b11..c0f95b4a 100644 --- a/.github/workflows/test-migration.yaml +++ b/.github/workflows/test-migration.yaml @@ -33,6 +33,8 @@ jobs: BOLT_GEM: true BOLT_DISABLE_ANALYTICS: true LANG: en_US.UTF-8 + PUPPET_FORGE_TOKEN: ${{ secrets.PUPPET_FORGE_TOKEN }} + BUNDLE_RUBYGEMS___PUPPETCORE__PUPPET__COM: forge-key:${{ secrets.PUPPET_FORGE_TOKEN }} strategy: fail-fast: false matrix: @@ -59,10 +61,10 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} - - name: Activate Ruby 2.7 + - name: Activate Ruby 3.2 uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.2' bundler-cache: true - name: Print bundle environment if: ${{ github.repository_owner == 'puppetlabs' }} diff --git a/.github/workflows/validate-puppetcore-gem-sources.yml b/.github/workflows/validate-puppetcore-gem-sources.yml new file mode 100644 index 00000000..38bf0916 --- /dev/null +++ b/.github/workflows/validate-puppetcore-gem-sources.yml @@ -0,0 +1,32 @@ +--- +name: Validate Puppetcore Gem Sources +on: + workflow_dispatch: + inputs: + ref: + description: Branch, tag or SHA to checkout + required: true + default: main +jobs: + verify-gemfile: + runs-on: ubuntu-latest + name: Verify Gemfile Dependencies + env: + PUPPET_FORGE_TOKEN: ${{ secrets.PUPPET_FORGE_TOKEN }} + BUNDLE_RUBYGEMS___PUPPETCORE__PUPPET__COM: forge-key:${{ secrets.PUPPET_FORGE_TOKEN }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref }} + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + cache-version: 0 # Helps manage cache versions explicitly + working-directory: . + - name: Install dependencies + run: bundle install + - name: Run Gemfile verification test + run: bundle exec rspec spec/support/gemfile_spec.rb --format documentation diff --git a/Gemfile b/Gemfile index 38a26f68..02896154 100644 --- a/Gemfile +++ b/Gemfile @@ -49,18 +49,21 @@ group :release_prep do gem "puppetlabs_spec_helper", '~> 6.0', require: false end -puppet_version = ENV['PUPPET_GEM_VERSION'] -facter_version = ENV['FACTER_GEM_VERSION'] -hiera_version = ENV['HIERA_GEM_VERSION'] - gems = {} +puppet_version = ENV.fetch('PUPPET_GEM_VERSION', nil) +facter_version = ENV.fetch('FACTER_GEM_VERSION', nil) +hiera_version = ENV.fetch('HIERA_GEM_VERSION', nil) -gems['puppet'] = location_for(puppet_version) - -# If facter or hiera versions have been specified via the environment -# variables +# If PUPPET_FORGE_TOKEN is set then use authenticated source for both puppet and facter, since facter is a transitive dependency of puppet +# Otherwise, do as before and use location_for to fetch gems from the default source +if !ENV['PUPPET_FORGE_TOKEN'].to_s.empty? + gems['puppet'] = [puppet_version || '~> 8.11', { require: false, source: 'https://rubygems-puppetcore.puppet.com' }] + gems['facter'] = [facter_version || '~> 4.0', { require: false, source: 'https://rubygems-puppetcore.puppet.com' }] +else + gems['puppet'] = location_for(puppet_version) + gems['facter'] = location_for(facter_version) if facter_version +end -gems['facter'] = location_for(facter_version) if facter_version gems['hiera'] = location_for(hiera_version) if hiera_version gems.each do |gem_name, gem_params| diff --git a/spec/support/gemfile_spec.rb b/spec/support/gemfile_spec.rb new file mode 100644 index 00000000..f9db3b42 --- /dev/null +++ b/spec/support/gemfile_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'bundler' + +RSpec.describe 'Gemfile.lock verification' do + let(:parser) { Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile)) } + let(:private_source) { 'https://rubygems-puppetcore.puppet.com/' } + let(:public_source) { 'https://rubygems.org/' } + let(:auth_token_present?) { !ENV['PUPPET_FORGE_TOKEN'].nil? } + + # Helper method to get source remotes for a specific gem + def get_gem_source_remotes(gem_name) + spec = parser.specs.find { |s| s.name == gem_name } + return [] unless spec + + source = spec.source + return [] unless source.is_a?(Bundler::Source::Rubygems) + + source.remotes.map(&:to_s) + end + + context 'when PUPPET_FORGE_TOKEN is present' do + before(:each) do + skip 'Skipping private source tests - PUPPET_FORGE_TOKEN not present' unless auth_token_present? + end + + it 'has puppet under private source' do + remotes = get_gem_source_remotes('puppet') + expect(remotes).to eq([private_source]), + "Expected puppet to use private source #{private_source}, got: #{remotes.join(', ')}" + expect(remotes).not_to eq([public_source]), + "Expected puppet to not use public source #{public_source}, got: #{remotes.join(', ')}" + end + + it 'has facter under private source' do + remotes = get_gem_source_remotes('facter') + expect(remotes).to eq([private_source]), + "Expected facter to use private source #{private_source}, got: #{remotes.join(', ')}" + expect(remotes).not_to eq([public_source]), + "Expected facter to not use public source #{public_source}, got: #{remotes.join(', ')}" + end + end + + context 'when PUPPET_FORGE_TOKEN is not present' do + before(:each) do + skip 'Skipping public source tests - PUPPET_FORGE_TOKEN is present' if auth_token_present? + end + + it 'has puppet under public source' do + remotes = get_gem_source_remotes('puppet') + expect(remotes).to eq([public_source]), + "Expected puppet to use public source #{public_source}, got: #{remotes.join(', ')}" + expect(remotes).not_to eq([private_source]), + "Expected puppet to not use private source #{private_source}, got: #{remotes.join(', ')}" + end + + it 'has facter under public source' do + remotes = get_gem_source_remotes('facter') + expect(remotes).to eq([public_source]), + "Expected facter to use public source #{public_source}, got: #{remotes.join(', ')}" + expect(remotes).not_to eq([private_source]), + "Expected facter to not use private source #{private_source}, got: #{remotes.join(', ')}" + end + end +end