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

(PDK-1342) Submit PDK analytics events #668

Merged
merged 1 commit into from
Jun 5, 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
15 changes: 8 additions & 7 deletions lib/pdk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
module PDK
def self.analytics
@analytics ||= PDK::Analytics.build_client(
logger: PDK.logger,
disabled: ENV['PDK_DISABLE_ANALYTICS'] || PDK.config.user['analytics']['disabled'],
user_id: PDK.config.user['analytics']['user-id'],
app_id: "UA-139917834-#{PDK::Util.development_mode? ? '2' : '1'}",
client: :google_analytics,
app_name: 'pdk',
app_version: PDK::VERSION,
logger: PDK.logger,
disabled: ENV['PDK_DISABLE_ANALYTICS'] || PDK.config.user['analytics']['disabled'],
user_id: PDK.config.user['analytics']['user-id'],
app_id: "UA-139917834-#{PDK::Util.development_mode? ? '2' : '1'}",
client: :google_analytics,
app_name: 'pdk',
app_version: PDK::VERSION,
app_installer: PDK::Util.package_install? ? 'package' : 'gem',
)
end
end
23 changes: 15 additions & 8 deletions lib/pdk/analytics/client/google_analytics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ class GoogleAnalytics
CUSTOM_DIMENSIONS = {
operating_system: :cd1,
output_format: :cd2,
ruby_version: :cd3,
cli_options: :cd4,
env_vars: :cd5,
}.freeze

attr_reader :user_id
attr_reader :logger
attr_reader :app_name
attr_reader :app_id
attr_reader :app_version
attr_reader :app_installer

def initialize(opts)
# lazy-load expensive gem code
Expand All @@ -30,6 +34,7 @@ def initialize(opts)
@app_name = opts[:app_name]
@app_id = opts[:app_id]
@app_version = opts[:app_version]
@app_installer = opts[:app_installer]
end

def screen_view(screen, **kwargs)
Expand Down Expand Up @@ -83,21 +88,23 @@ def submit(params)
# https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
def base_params
{
v: PROTOCOL_VERSION,
v: PROTOCOL_VERSION,
# Client ID
cid: user_id,
cid: user_id,
# Tracking ID
tid: app_id,
tid: app_id,
# Application Name
an: app_name,
an: app_name,
# Application Version
av: app_version,
av: app_version,
# Application Installer ID
aiid: app_installer,
# Anonymize IPs
aip: true,
aip: true,
# User locale
ul: Locale.current.to_rfc,
ul: Locale.current.to_rfc,
# Custom Dimension 1 (Operating System)
cd1: @os.value,
cd1: @os.value,
}
end

Expand Down
36 changes: 36 additions & 0 deletions lib/pdk/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,44 @@
require 'pdk/util/version'
require 'pdk/util/puppet_version'

class Cri::Command::CriExitException
def initialize(is_error:)
@is_error = is_error
PDK.analytics.event('CLI', 'invalid command', label: PDK::CLI.anonymised_args.join(' ')) if error?
end
end

module PDK::CLI
# Attempt to anonymise the raw ARGV array if the command parsing failed.
#
# If an item does not start with '-' but is preceeded by an item that does
# start with '-', assume that these items are an option/value pair and redact
# the value. Any additional values that do not start with '-' that follow an
# option/value pair are assumed to be arguments (rather than subcommand
# names) and are also redacted.
#
# @example
# # Where PDK::CLI.args => ['new', 'plan', '--some', 'value', 'plan_name']
#
# PDK::CLI.anonymised_args
# => ['new', 'plan', '--some', 'redacted', 'redacted']
#
# @return Array[String] the command arguments with any identifying values
# redacted.
def self.anonymised_args
rodjek marked this conversation as resolved.
Show resolved Hide resolved
in_args = false
@args.map do |arg|
if arg.start_with?('-')
in_args = true
arg
else
in_args ? 'redacted' : arg
end
end
end

def self.run(args)
@args = args
PDK::Config.analytics_config_interview! unless PDK::Config.analytics_config_exist?
@base_cmd.run(args)
rescue PDK::CLI::ExitWithError => e
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module PDK::CLI
log_level: :info,
)

PDK::CLI::Util.analytics_screen_view('build', opts)

module_metadata = PDK::Module::Metadata.from_file('metadata.json')

# TODO: Ensure forge metadata has been set, or call out to interview
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/bundle.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ module PDK::CLI

PDK::CLI::Util.validate_puppet_version_opts({})

PDK::CLI::Util.analytics_screen_view('bundle')

# Ensure that the correct Ruby is activated before running commend.
puppet_env = PDK::CLI::Util.puppet_from_opts_or_env({})
PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/convert.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _('You can not specify --noop and --force when converting a module')
end

PDK::CLI::Util.analytics_screen_view('convert', opts)

if opts[:'skip-interview'] && opts[:'full-interview']
PDK.logger.info _('Ignoring --full-interview and continuing with --skip-interview.')
opts[:'full-interview'] = false
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/new/class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid class name") % { name: class_name }
end

PDK::CLI::Util.analytics_screen_view('new_class', opts)

PDK::Generate::PuppetClass.new(module_dir, class_name, opts).run
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/new/defined_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid defined type name") % { name: defined_type_name }
end

PDK::CLI::Util.analytics_screen_view('new_defined_type', opts)

PDK::Generate::DefinedType.new(module_dir, defined_type_name, opts).run
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/pdk/cli/new/module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ module PDK::CLI

PDK::CLI::Util.validate_template_opts(opts)

PDK::CLI::Util.analytics_screen_view('new_module', opts)

if opts[:'skip-interview'] && opts[:'full-interview']
PDK.logger.info _('Ignoring --full-interview and continuing with --skip-interview.')
opts[:'full-interview'] = false
Expand All @@ -37,8 +39,6 @@ module PDK::CLI
opts[:target_dir] = target_dir.nil? ? opts[:module_name] : target_dir
end

PDK.analytics.screen_view('new_module')

PDK.logger.info(_('Creating new module: %{modname}') % { modname: module_name })
PDK::Generate::Module.invoke(opts)
end
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/new/provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid provider name") % { name: provider_name }
end

PDK::CLI::Util.analytics_screen_view('new_provider', opts)

PDK::Generate::Provider.new(module_dir, provider_name, opts).run
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/new/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid task name") % { name: task_name }
end

PDK::CLI::Util.analytics_screen_view('new_task', opts)

PDK::Generate::Task.new(module_dir, task_name, opts).run
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/test/unit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ module PDK::CLI

PDK::CLI::Util.module_version_check

PDK::CLI::Util.analytics_screen_view('test_unit', opts)

# Ensure that the bundled gems are up to date and correct Ruby is activated before running or listing tests.
puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
PDK::Util::PuppetVersion.fetch_puppet_dev if opts[:'puppet-dev']
Expand Down
2 changes: 2 additions & 0 deletions lib/pdk/cli/update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module PDK::CLI
raise PDK::CLI::ExitWithError, _('You can not specify --noop and --force when updating a module')
end

PDK::CLI::Util.analytics_screen_view('update', opts)

updater = PDK::Module::Update.new(opts)

updater.run
Expand Down
35 changes: 35 additions & 0 deletions lib/pdk/cli/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,41 @@ def validate_template_opts(opts)
raise PDK::CLI::ExitWithError, _('--template-url may not be used to specify paths containing #\'s.')
end
module_function :validate_template_opts

def analytics_screen_view(screen_name, opts = {})
dimensions = {
ruby_version: RUBY_VERSION,
}

cmd_opts = opts.dup.reject do |_, v|
v.nil? || (v.respond_to?(:empty?) && v.empty?)
end

if (format_args = cmd_opts.delete(:format))
formats = PDK::CLI::Util::OptionNormalizer.report_formats(format_args)
dimensions[:output_format] = formats.map { |r| r[:method].to_s.gsub(%r{\Awrite_}, '') }.sort.uniq.join(',')
else
dimensions[:output_format] = 'default'
end

safe_opts = [:'puppet-version', :'pe-version']
redacted_opts = cmd_opts.map do |k, v|
value = if [true, false].include?(v) || safe_opts.include?(k)
v
else
'redacted'
end
"#{k}=#{value}"
end
dimensions[:cli_options] = redacted_opts.join(',') unless redacted_opts.empty?

ignored_env_vars = %w[PDK_ANALYTICS_CONFIG PDK_DISABLE_ANALYTICS]
env_vars = ENV.select { |k, _| k.start_with?('PDK_') && !ignored_env_vars.include?(k) }.map { |k, v| "#{k}=#{v}" }
dimensions[:env_vars] = env_vars.join(',') unless env_vars.empty?

PDK.analytics.screen_view(screen_name, dimensions)
end
module_function :analytics_screen_view
end
end
end
7 changes: 7 additions & 0 deletions lib/pdk/cli/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module PDK::CLI
targets = []

if opts[:list]
PDK::CLI::Util.analytics_screen_view('validate', opts)
PDK.logger.info(_('Available validators: %{validator_names}') % { validator_names: validator_names.join(', ') })
exit 0
end
Expand Down Expand Up @@ -71,6 +72,12 @@ module PDK::CLI
PDK.logger.info(_('Running all available validators...'))
end

if validators == PDK::Validate.validators
PDK::CLI::Util.analytics_screen_view('validate', opts)
else
PDK::CLI::Util.analytics_screen_view(['validate', validators.map(&:name).sort].flatten.join('_'), opts)
end

# Subsequent arguments are targets.
targets.concat(args.to_a[1..-1]) if args.length > 1

Expand Down
2 changes: 1 addition & 1 deletion lib/pdk/generate/module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def self.prepare_metadata(opts = {})
defaults['name'] = "#{opts[:username]}-#{opts[:module_name]}" unless opts[:module_name].nil?
defaults['author'] = PDK.answers['author'] unless PDK.answers['author'].nil?
defaults['license'] = PDK.answers['license'] unless PDK.answers['license'].nil?
defaults['license'] = opts[:license] if opts.key? :license
defaults['license'] = opts[:license] if opts.key?(:license)

metadata = PDK::Module::Metadata.new(defaults)
module_interview(metadata, opts) unless opts[:'skip-interview']
Expand Down
23 changes: 20 additions & 3 deletions lib/pdk/module/templatedir.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ def initialize(uri, module_metadata = {}, init = false)

@module_metadata = module_metadata

template_type = uri.default? ? 'default' : 'custom'
PDK.analytics.event('TemplateDir', 'initialize', label: template_type)

yield self
ensure
# If we cloned a git repo to get the template, remove the clone once
Expand Down Expand Up @@ -256,14 +259,28 @@ def config_for(dest_path, sync_config_path = nil)

if @config.nil?
conf_defaults = read_config(config_path)
sync_config = read_config(sync_config_path) unless sync_config_path.nil?
@sync_config = read_config(sync_config_path) unless sync_config_path.nil?
@config = conf_defaults
@config.deep_merge!(sync_config, knockout_prefix: '---') unless sync_config.nil?
@config.deep_merge!(@sync_config, knockout_prefix: '---') unless @sync_config.nil?
end
file_config = @config.fetch(:global, {})
file_config['module_metadata'] = @module_metadata
file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
file_config.merge!(@config)
file_config.merge!(@config).tap do |c|
if uri.default?
file_value = if c['unmanaged']
'unmanaged'
elsif c['delete']
'deleted'
elsif @sync_config && @sync_config.key?(dest_path)
'customized'
else
'default'
end

PDK.analytics.event('TemplateDir', 'file', label: dest_path, value: file_value)
end
end
end

# Generates a hash of data from a given yaml file location.
Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper_acceptance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def execute_script(script)
puts "Working in #{tempdir}"

analytics_config = Tempfile.new('analytics.yml')
analytics_config.write(YAML.dump(disabled: true))
analytics_config.write(YAML.dump('disabled' => true))
analytics_config.close
ENV['PDK_ANALYTICS_CONFIG'] = analytics_config.path
end
Expand Down
1 change: 1 addition & 0 deletions spec/unit/pdk/analytics/client/google_analytics_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
av: options[:app_version],
cid: options[:user_id],
tid: options[:app_id],
aiid: options[:app_installer],
ul: Locale.current.to_rfc,
aip: true,
cd1: os_name,
Expand Down
Loading