Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(GH-808) Implement pdk release prep and publish subcommands #813

Merged
merged 2 commits into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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).not_to receive(:new)

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).not_to receive(:new)

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).not_to receive(:new)

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
Loading