Skip to content

Commit

Permalink
(GH-808) Implement pdk release prep and publish subcommands
Browse files Browse the repository at this point in the history
Previously the pdk release command was added.  This commit adds the prep and
publish subcommands as per PDK RFC 003.

This commit also adds tests for new subcommands.
  • Loading branch information
glennsarti committed Dec 6, 2019
1 parent 269b478 commit c354423
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 12 deletions.
31 changes: 22 additions & 9 deletions lib/pdk/cli/release.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,23 @@ module PDK::CLI
log_level: :info,
)

unless opts[:force]
Release.prepare_interview(opts)
end
Release.prepare_interview(opts) unless opts[:force]

# Don't pass tokens to analytics
PDK::CLI::Util.analytics_screen_view('release', opts.reject { |k, _| k == :'forge-token' })
Release.send_analytics('release', opts)

release = PDK::Module::Release.new(nil, opts)

Release.module_compatibility_checks!(release, opts)

release.run
end
end

module Release
# Checks whether the module is compatible with PDK release process
# @param release PDK::Module::Release Object representing the release
# @param opts Options Hash from Cri
def self.module_compatibility_checks!(release, opts)
unless release.module_metadata.forge_ready?
if opts[:force]
PDK.logger.warn _(
Expand All @@ -60,7 +68,7 @@ module PDK::CLI
end
end

unless release.pdk_compatible?
unless release.pdk_compatible? # rubocop:disable Style/GuardClause Nope!
if opts[:force]
PDK.logger.warn _('This module is not compatible with PDK, so PDK can not validate or test this build.')
else
Expand All @@ -73,12 +81,14 @@ module PDK::CLI
end
end
end
end

release.run
# Send_analytics for the given command and Cri options
def self.send_analytics(command, opts)
# Don't pass tokens to analytics
PDK::CLI::Util.analytics_screen_view(command, opts.reject { |k, _| k == :'forge-token' })
end
end

module Release
def self.prepare_interview(opts)
questions = []

Expand Down Expand Up @@ -177,3 +187,6 @@ def self.prepare_publish_interview(prompt, opts)
end
end
end

require 'pdk/cli/release/prep'
require 'pdk/cli/release/publish'
39 changes: 39 additions & 0 deletions lib/pdk/cli/release/prep.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'pdk/cli/release'

module PDK::CLI
@release_prep_cmd = @release_cmd.define_command do
name 'prep'
usage _('prep [options]')
summary _('(Experimental) Performs all the pre-release checks to ensure module is ready to be released')

flag nil, :force, _('Prepare the module automatically, with no prompts.')
flag nil, :'skip-validation', _('Skips the module validation check.')
flag nil, :'skip-changelog', _('Skips the automatic changelog generation.')
flag nil, :'skip-dependency', _('Skips the module dependency check.')
flag nil, :'skip-documentation', _('Skips the documentation update.')

option nil, :version, _('Update the module to the specified version prior to release. When not specified, the new version will be computed from the Changelog where possible.'),
argument: :required

run do |opts, _args, cmd|
# Make sure build is being run in a valid module directory with a metadata.json
PDK::CLI::Util.ensure_in_module!(
message: _("`pdk release #{cmd.name}` can only be run from inside a valid module with a metadata.json."),
log_level: :info,
)

opts[:'skip-build'] = true
opts[:'skip-publish'] = true

Release.prepare_interview(opts) unless opts[:force]

Release.send_analytics("release #{cmd.name}", opts)

release = PDK::Module::Release.new(nil, opts)

Release.module_compatibility_checks!(release, opts)

release.run
end
end
end
40 changes: 40 additions & 0 deletions lib/pdk/cli/release/publish.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'pdk/cli/release'

module PDK::CLI
@release_publish_cmd = @release_cmd.define_command do
name 'publish'
usage _('publish [options] <tarball>')
summary _('(Experimental) Publishes the module <tarball> to the Forge.')

flag nil, :force, _('Publish the module automatically, with no prompts.')

option nil, :'forge-upload-url', _('Set forge upload url path.'),
argument: :required, default: 'https://forgeapi.puppetlabs.com/v3/releases'

option nil, :'forge-token', _('Set Forge API token.'), argument: :required, default: nil

run do |opts, _args, cmd|
# Make sure build is being run in a valid module directory with a metadata.json
PDK::CLI::Util.ensure_in_module!(
message: _("`pdk release #{cmd.name}` can only be run from inside a valid module with a metadata.json."),
log_level: :info,
)

opts[:'skip-validation'] = true
opts[:'skip-changelog'] = true
opts[:'skip-dependency'] = true
opts[:'skip-documentation'] = true
opts[:'skip-build'] = true
opts[:'skip-versionset'] = true
opts[:force] = true unless PDK::CLI::Util.interactive?

Release.prepare_publish_interview(TTY::Prompt.new(help_color: :cyan), opts) unless opts[:force]

Release.send_analytics("release #{cmd.name}", opts)

release = PDK::Module::Release.new(nil, opts)

release.run
end
end
end
71 changes: 71 additions & 0 deletions spec/unit/pdk/cli/release/prep_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
require 'spec_helper'
require 'pdk/cli'

describe 'PDK::CLI release prep' do
let(:help_text) { a_string_matching(%r{^USAGE\s+pdk release prep}m) }
let(:cli_args) { %w[release prep] }

context 'when not run from inside a module' do
include_context 'run outside module'

it 'exits with an error' do
expect(logger).to receive(:error).with(a_string_matching(%r{must be run from inside a valid module}))

expect { PDK::CLI.run(cli_args) }.to exit_nonzero
end

it 'does not submit the command to analytics' do
expect(analytics).not_to receive(:screen_view)

expect { PDK::CLI.run(cli_args) }.to exit_nonzero
end
end

context 'when run from inside a module' do
let(:release_object) do
instance_double(
PDK::Module::Release,
pdk_compatible?: true,
module_metadata: mock_metadata_obj,
run: nil,
)
end

let(:mock_metadata_obj) do
instance_double(
PDK::Module::Metadata,
forge_ready?: true,
)
end

before(:each) do
allow(PDK::CLI::Util).to receive(:ensure_in_module!).and_return(nil)
allow(PDK::Module::Release).to receive(:new).and_return(release_object)
allow(PDK::Util).to receive(:exit_process).and_raise('exit_process mock should not be called')
end

it 'calls PDK::Module::Release.run' do
expect(release_object).to receive(:run)

expect { PDK::CLI.run(cli_args.concat(%w[--force])) }.not_to raise_error
end

it 'skips building and publishing' do
expect(PDK::Module::Release).to receive(:new).with(Object, hash_including(:'skip-build' => true, :'skip-publish' => true))

expect { PDK::CLI.run(cli_args.concat(%w[--force])) }.not_to raise_error
end

it 'does not start an interview when --force is used' do
expect(PDK::CLI::Util::Interview).to receive(:new).never

PDK::CLI.run(cli_args.concat(%w[--force]))
end

it 'calls PDK::CLI::Release.module_compatibility_checks!' do
expect(PDK::CLI::Release).to receive(:module_compatibility_checks!).and_return(nil)

expect { PDK::CLI.run(cli_args.concat(%w[--force])) }.not_to raise_error
end
end
end
81 changes: 81 additions & 0 deletions spec/unit/pdk/cli/release/publish_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require 'spec_helper'
require 'pdk/cli'

describe 'PDK::CLI release publish' do
let(:help_text) { a_string_matching(%r{^USAGE\s+pdk release publish}m) }
let(:cli_args) { %w[release publish] }

context 'when not run from inside a module' do
include_context 'run outside module'

it 'exits with an error' do
expect(logger).to receive(:error).with(a_string_matching(%r{must be run from inside a valid module}))

expect { PDK::CLI.run(cli_args) }.to exit_nonzero
end

it 'does not submit the command to analytics' do
expect(analytics).not_to receive(:screen_view)

expect { PDK::CLI.run(cli_args) }.to exit_nonzero
end
end

context 'when run from inside a module' do
let(:release_object) do
instance_double(
PDK::Module::Release,
pdk_compatible?: true,
module_metadata: mock_metadata_obj,
run: nil,
)
end

let(:mock_metadata_obj) do
instance_double(
PDK::Module::Metadata,
forge_ready?: true,
)
end

before(:each) do
allow(PDK::CLI::Util).to receive(:ensure_in_module!).and_return(nil)
allow(PDK::Module::Release).to receive(:new).and_return(release_object)
allow(PDK::Util).to receive(:exit_process).and_raise('exit_process mock should not be called')
end

it 'calls PDK::Module::Release.run' do
expect(release_object).to receive(:run)

expect { PDK::CLI.run(cli_args.concat(%w[--force])) }.not_to raise_error
end

it 'skips all but publishing' do
expect(PDK::Module::Release).to receive(:new).with(
Object,
hash_including(
:'skip-validation' => true,
:'skip-changelog' => true,
:'skip-dependency' => true,
:'skip-documentation' => true,
:'skip-build' => true,
),
)

expect { PDK::CLI.run(cli_args.concat(%w[--force])) }.not_to raise_error
end

it 'does not start an interview when --force is used' do
expect(PDK::CLI::Util::Interview).to receive(:new).never

PDK::CLI.run(cli_args.concat(%w[--force]))
end

it 'implicitly uses --force in non-interactive environments' do
allow(PDK::CLI::Util).to receive(:interactive?).and_return(false)
expect(PDK::Module::Release).to receive(:new).with(Object, hash_including(force: true))

expect { PDK::CLI.run(cli_args) }.not_to raise_error
end
end
end
62 changes: 59 additions & 3 deletions spec/unit/pdk/cli/release_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
require 'pdk/cli'

describe 'PDK::CLI release' do
let(:help_text) { a_string_matching(%r{^USAGE\s+pdk release}m) }

context 'when not run from inside a module' do
include_context 'run outside module'

Expand All @@ -19,6 +17,7 @@
PDK::Module::Release,
pdk_compatible?: true,
module_metadata: mock_metadata_obj,
run: nil,
)
end

Expand All @@ -33,11 +32,68 @@
allow(PDK::CLI::Util).to receive(:ensure_in_module!).and_return(nil)
allow(PDK::Module::Release).to receive(:new).and_return(release_object)
allow(PDK::Util).to receive(:exit_process).and_raise('exit_process mock should not be called')
expect(release_object).to receive(:run).and_return(nil)
end

it 'calls PDK::Module::Release.run' do
expect(release_object).to receive(:run).and_return(nil)

expect { PDK::CLI.run(%w[release --force]) }.not_to raise_error
end

it 'does not start an interview when --force is used' do
expect(PDK::CLI::Util::Interview).to receive(:new).never

PDK::CLI.run(%w[release --force])
end

it 'calls PDK::CLI::Release.module_compatibility_checks!' do
expect(PDK::CLI::Release).to receive(:module_compatibility_checks!).and_return(nil)

expect { PDK::CLI.run(%w[release --force]) }.not_to raise_error
end
end

describe '#module_compatibility_checks!' do
let(:release_object) do
instance_double(
PDK::Module::Release,
pdk_compatible?: true,
module_metadata: mock_metadata_obj,
run: nil,
)
end

let(:mock_metadata_obj) do
instance_double(
PDK::Module::Metadata,
forge_ready?: true,
)
end

let(:opts) { { force: true } }
let(:release) { PDK::CLI::Release }

context 'With a module that is not forge ready' do
before(:each) do
allow(mock_metadata_obj).to receive(:forge_ready?).and_return(false)
allow(mock_metadata_obj).to receive(:missing_fields).and_return(['mock_field'])
end

it 'raises a warning' do
expect(PDK.logger).to receive(:warn).with(%r{mock_field})
release.module_compatibility_checks!(release_object, opts)
end
end

context 'With a module that is not pdk compatibler' do
before(:each) do
allow(release_object).to receive(:pdk_compatible?).and_return(false)
end

it 'raises a warning' do
expect(PDK.logger).to receive(:warn).with(%r{not compatible with PDK})
release.module_compatibility_checks!(release_object, opts)
end
end
end
end

0 comments on commit c354423

Please sign in to comment.