pantograph 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/LICENSE +21 -0
- data/README.md +197 -0
- data/bin/bin-proxy +19 -0
- data/bin/pantograph +23 -0
- data/pantograph/README.md +11 -0
- data/pantograph/lib/assets/ActionDetails.md.erb +106 -0
- data/pantograph/lib/assets/Actions.md.erb +43 -0
- data/pantograph/lib/assets/DefaultPantfileTemplate +20 -0
- data/pantograph/lib/assets/completions/completion.bash +23 -0
- data/pantograph/lib/assets/completions/completion.fish +39 -0
- data/pantograph/lib/assets/completions/completion.sh +12 -0
- data/pantograph/lib/assets/completions/completion.zsh +23 -0
- data/pantograph/lib/assets/custom_action_template.rb +80 -0
- data/pantograph/lib/assets/report_template.xml.erb +15 -0
- data/pantograph/lib/pantograph/action.rb +194 -0
- data/pantograph/lib/pantograph/action_collector.rb +35 -0
- data/pantograph/lib/pantograph/actions/README.md +3 -0
- data/pantograph/lib/pantograph/actions/actions_helper.rb +166 -0
- data/pantograph/lib/pantograph/actions/add_extra_platforms.rb +45 -0
- data/pantograph/lib/pantograph/actions/artifactory.rb +157 -0
- data/pantograph/lib/pantograph/actions/bundle_install.rb +156 -0
- data/pantograph/lib/pantograph/actions/changelog_from_git_commits.rb +197 -0
- data/pantograph/lib/pantograph/actions/clipboard.rb +52 -0
- data/pantograph/lib/pantograph/actions/cloc.rb +89 -0
- data/pantograph/lib/pantograph/actions/create_pull_request.rb +190 -0
- data/pantograph/lib/pantograph/actions/danger.rb +131 -0
- data/pantograph/lib/pantograph/actions/debug.rb +32 -0
- data/pantograph/lib/pantograph/actions/default_platform.rb +47 -0
- data/pantograph/lib/pantograph/actions/download.rb +76 -0
- data/pantograph/lib/pantograph/actions/echo.rb +14 -0
- data/pantograph/lib/pantograph/actions/ensure_bundle_exec.rb +59 -0
- data/pantograph/lib/pantograph/actions/ensure_env_vars.rb +58 -0
- data/pantograph/lib/pantograph/actions/ensure_git_branch.rb +69 -0
- data/pantograph/lib/pantograph/actions/ensure_git_status_clean.rb +81 -0
- data/pantograph/lib/pantograph/actions/erb.rb +88 -0
- data/pantograph/lib/pantograph/actions/get_build_number_repository.rb +120 -0
- data/pantograph/lib/pantograph/actions/get_github_release.rb +163 -0
- data/pantograph/lib/pantograph/actions/git_add.rb +93 -0
- data/pantograph/lib/pantograph/actions/git_branch.rb +58 -0
- data/pantograph/lib/pantograph/actions/git_commit.rb +80 -0
- data/pantograph/lib/pantograph/actions/git_pull.rb +53 -0
- data/pantograph/lib/pantograph/actions/git_submodule_update.rb +52 -0
- data/pantograph/lib/pantograph/actions/git_tag_exists.rb +74 -0
- data/pantograph/lib/pantograph/actions/github_api.rb +262 -0
- data/pantograph/lib/pantograph/actions/gradle.rb +278 -0
- data/pantograph/lib/pantograph/actions/import.rb +49 -0
- data/pantograph/lib/pantograph/actions/import_from_git.rb +71 -0
- data/pantograph/lib/pantograph/actions/is_ci.rb +51 -0
- data/pantograph/lib/pantograph/actions/jira.rb +115 -0
- data/pantograph/lib/pantograph/actions/lane_context.rb +60 -0
- data/pantograph/lib/pantograph/actions/last_git_commit.rb +58 -0
- data/pantograph/lib/pantograph/actions/last_git_tag.rb +51 -0
- data/pantograph/lib/pantograph/actions/make_changelog_from_jenkins.rb +81 -0
- data/pantograph/lib/pantograph/actions/min_pantograph_version.rb +57 -0
- data/pantograph/lib/pantograph/actions/nexus_upload.rb +230 -0
- data/pantograph/lib/pantograph/actions/notification.rb +75 -0
- data/pantograph/lib/pantograph/actions/number_of_commits.rb +75 -0
- data/pantograph/lib/pantograph/actions/opt_out_usage.rb +40 -0
- data/pantograph/lib/pantograph/actions/pantograph_version.rb +15 -0
- data/pantograph/lib/pantograph/actions/println.rb +14 -0
- data/pantograph/lib/pantograph/actions/prompt.rb +119 -0
- data/pantograph/lib/pantograph/actions/push_git_tags.rb +76 -0
- data/pantograph/lib/pantograph/actions/push_to_git_remote.rb +127 -0
- data/pantograph/lib/pantograph/actions/puts.rb +68 -0
- data/pantograph/lib/pantograph/actions/reset_git_repo.rb +121 -0
- data/pantograph/lib/pantograph/actions/rocket.rb +83 -0
- data/pantograph/lib/pantograph/actions/rsync.rb +74 -0
- data/pantograph/lib/pantograph/actions/ruby_version.rb +56 -0
- data/pantograph/lib/pantograph/actions/say.rb +56 -0
- data/pantograph/lib/pantograph/actions/scp.rb +114 -0
- data/pantograph/lib/pantograph/actions/set_github_release.rb +274 -0
- data/pantograph/lib/pantograph/actions/sh.rb +71 -0
- data/pantograph/lib/pantograph/actions/skip_docs.rb +52 -0
- data/pantograph/lib/pantograph/actions/slack.rb +288 -0
- data/pantograph/lib/pantograph/actions/sonar.rb +156 -0
- data/pantograph/lib/pantograph/actions/ssh.rb +162 -0
- data/pantograph/lib/pantograph/actions/twitter.rb +89 -0
- data/pantograph/lib/pantograph/actions/update_pantograph.rb +177 -0
- data/pantograph/lib/pantograph/actions/zip.rb +120 -0
- data/pantograph/lib/pantograph/auto_complete.rb +82 -0
- data/pantograph/lib/pantograph/boolean.rb +5 -0
- data/pantograph/lib/pantograph/cli_tools_distributor.rb +183 -0
- data/pantograph/lib/pantograph/command_line_handler.rb +43 -0
- data/pantograph/lib/pantograph/commands_generator.rb +344 -0
- data/pantograph/lib/pantograph/configuration_helper.rb +26 -0
- data/pantograph/lib/pantograph/core_ext/bundler_monkey_patch.rb +14 -0
- data/pantograph/lib/pantograph/documentation/actions_list.rb +214 -0
- data/pantograph/lib/pantograph/documentation/docs_generator.rb +95 -0
- data/pantograph/lib/pantograph/documentation/markdown_docs_generator.rb +221 -0
- data/pantograph/lib/pantograph/environment_printer.rb +282 -0
- data/pantograph/lib/pantograph/erb_template_helper.rb +30 -0
- data/pantograph/lib/pantograph/features.rb +4 -0
- data/pantograph/lib/pantograph/helper/README.md +29 -0
- data/pantograph/lib/pantograph/helper/dotenv_helper.rb +50 -0
- data/pantograph/lib/pantograph/helper/gem_helper.rb +26 -0
- data/pantograph/lib/pantograph/helper/git_helper.rb +135 -0
- data/pantograph/lib/pantograph/helper/gradle_helper.rb +62 -0
- data/pantograph/lib/pantograph/helper/sh_helper.rb +134 -0
- data/pantograph/lib/pantograph/junit_generator.rb +27 -0
- data/pantograph/lib/pantograph/lane.rb +97 -0
- data/pantograph/lib/pantograph/lane_list.rb +77 -0
- data/pantograph/lib/pantograph/lane_manager.rb +140 -0
- data/pantograph/lib/pantograph/lane_manager_base.rb +92 -0
- data/pantograph/lib/pantograph/markdown_table_formatter.rb +62 -0
- data/pantograph/lib/pantograph/new_action.rb +47 -0
- data/pantograph/lib/pantograph/one_off.rb +45 -0
- data/pantograph/lib/pantograph/other_action.rb +29 -0
- data/pantograph/lib/pantograph/pant_file.rb +377 -0
- data/pantograph/lib/pantograph/pantograph_require.rb +75 -0
- data/pantograph/lib/pantograph/plugins/plugin_fetcher.rb +55 -0
- data/pantograph/lib/pantograph/plugins/plugin_generator.rb +86 -0
- data/pantograph/lib/pantograph/plugins/plugin_generator_ui.rb +19 -0
- data/pantograph/lib/pantograph/plugins/plugin_info.rb +49 -0
- data/pantograph/lib/pantograph/plugins/plugin_info_collector.rb +159 -0
- data/pantograph/lib/pantograph/plugins/plugin_manager.rb +387 -0
- data/pantograph/lib/pantograph/plugins/plugin_search.rb +46 -0
- data/pantograph/lib/pantograph/plugins/plugin_update_manager.rb +70 -0
- data/pantograph/lib/pantograph/plugins/plugins.rb +12 -0
- data/pantograph/lib/pantograph/plugins/template/%gem_name%.gemspec.erb +35 -0
- data/pantograph/lib/pantograph/plugins/template/.circleci/config.yml +43 -0
- data/pantograph/lib/pantograph/plugins/template/.gitignore +12 -0
- data/pantograph/lib/pantograph/plugins/template/.rspec +5 -0
- data/pantograph/lib/pantograph/plugins/template/.rubocop.yml +179 -0
- data/pantograph/lib/pantograph/plugins/template/.travis.yml +4 -0
- data/pantograph/lib/pantograph/plugins/template/Gemfile +6 -0
- data/pantograph/lib/pantograph/plugins/template/LICENSE.erb +21 -0
- data/pantograph/lib/pantograph/plugins/template/README.md.erb +52 -0
- data/pantograph/lib/pantograph/plugins/template/Rakefile +9 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/actions/%plugin_name%_action.rb.erb +47 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/helper/%plugin_name%_helper.rb.erb +16 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%/version.rb.erb +5 -0
- data/pantograph/lib/pantograph/plugins/template/lib/pantograph/plugin/%plugin_name%.rb.erb +16 -0
- data/pantograph/lib/pantograph/plugins/template/pantograph/Pantfile.erb +3 -0
- data/pantograph/lib/pantograph/plugins/template/pantograph/Pluginfile.erb +1 -0
- data/pantograph/lib/pantograph/plugins/template/spec/%plugin_name%_action_spec.rb.erb +9 -0
- data/pantograph/lib/pantograph/plugins/template/spec/spec_helper.rb.erb +15 -0
- data/pantograph/lib/pantograph/runner.rb +371 -0
- data/pantograph/lib/pantograph/server/action_command.rb +61 -0
- data/pantograph/lib/pantograph/server/action_command_return.rb +14 -0
- data/pantograph/lib/pantograph/server/command_executor.rb +7 -0
- data/pantograph/lib/pantograph/server/command_parser.rb +36 -0
- data/pantograph/lib/pantograph/server/control_command.rb +23 -0
- data/pantograph/lib/pantograph/server/json_return_value_processor.rb +72 -0
- data/pantograph/lib/pantograph/server/socket_server.rb +232 -0
- data/pantograph/lib/pantograph/server/socket_server_action_command_executor.rb +101 -0
- data/pantograph/lib/pantograph/setup/setup.rb +290 -0
- data/pantograph/lib/pantograph/setup/setup_android.rb +64 -0
- data/pantograph/lib/pantograph/setup/setup_ios.rb +412 -0
- data/pantograph/lib/pantograph/shells.rb +6 -0
- data/pantograph/lib/pantograph/supported_platforms.rb +28 -0
- data/pantograph/lib/pantograph/tools.rb +10 -0
- data/pantograph/lib/pantograph/version.rb +5 -0
- data/pantograph/lib/pantograph.rb +51 -0
- data/pantograph_core/README.md +79 -0
- data/pantograph_core/lib/assets/XMLTemplate.xml.erb +12 -0
- data/pantograph_core/lib/pantograph_core/analytics/action_completion_context.rb +34 -0
- data/pantograph_core/lib/pantograph_core/analytics/action_launch_context.rb +38 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_event_builder.rb +23 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_ingester_client.rb +54 -0
- data/pantograph_core/lib/pantograph_core/analytics/analytics_session.rb +71 -0
- data/pantograph_core/lib/pantograph_core/cert_checker.rb +116 -0
- data/pantograph_core/lib/pantograph_core/command_executor.rb +99 -0
- data/pantograph_core/lib/pantograph_core/configuration/commander_generator.rb +103 -0
- data/pantograph_core/lib/pantograph_core/configuration/config_item.rb +314 -0
- data/pantograph_core/lib/pantograph_core/configuration/configuration.rb +332 -0
- data/pantograph_core/lib/pantograph_core/configuration/configuration_file.rb +182 -0
- data/pantograph_core/lib/pantograph_core/core_ext/shellwords.rb +63 -0
- data/pantograph_core/lib/pantograph_core/core_ext/string.rb +17 -0
- data/pantograph_core/lib/pantograph_core/env.rb +9 -0
- data/pantograph_core/lib/pantograph_core/feature/feature.rb +51 -0
- data/pantograph_core/lib/pantograph_core/features.rb +4 -0
- data/pantograph_core/lib/pantograph_core/globals.rb +27 -0
- data/pantograph_core/lib/pantograph_core/helper.rb +409 -0
- data/pantograph_core/lib/pantograph_core/keychain_importer.rb +74 -0
- data/pantograph_core/lib/pantograph_core/languages.rb +14 -0
- data/pantograph_core/lib/pantograph_core/module.rb +29 -0
- data/pantograph_core/lib/pantograph_core/pantograph_folder.rb +39 -0
- data/pantograph_core/lib/pantograph_core/pantograph_pty.rb +57 -0
- data/pantograph_core/lib/pantograph_core/pkg_file_analyser.rb +44 -0
- data/pantograph_core/lib/pantograph_core/print_table.rb +131 -0
- data/pantograph_core/lib/pantograph_core/string_filters.rb +51 -0
- data/pantograph_core/lib/pantograph_core/swag.rb +85 -0
- data/pantograph_core/lib/pantograph_core/tag_version.rb +31 -0
- data/pantograph_core/lib/pantograph_core/test_parser.rb +107 -0
- data/pantograph_core/lib/pantograph_core/ui/disable_colors.rb +17 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_common_error.rb +19 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_crash.rb +11 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_error.rb +25 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_exception.rb +19 -0
- data/pantograph_core/lib/pantograph_core/ui/errors/pantograph_shell_error.rb +11 -0
- data/pantograph_core/lib/pantograph_core/ui/errors.rb +1 -0
- data/pantograph_core/lib/pantograph_core/ui/github_issue_inspector_reporter.rb +62 -0
- data/pantograph_core/lib/pantograph_core/ui/implementations/shell.rb +159 -0
- data/pantograph_core/lib/pantograph_core/ui/interface.rb +205 -0
- data/pantograph_core/lib/pantograph_core/ui/pantograph_runner.rb +276 -0
- data/pantograph_core/lib/pantograph_core/ui/ui.rb +26 -0
- data/pantograph_core/lib/pantograph_core/update_checker/changelog.rb +37 -0
- data/pantograph_core/lib/pantograph_core/update_checker/update_checker.rb +107 -0
- data/pantograph_core/lib/pantograph_core.rb +45 -0
- metadata +987 -0
@@ -0,0 +1,314 @@
|
|
1
|
+
require_relative '../ui/ui'
|
2
|
+
require_relative '../ui/errors/pantograph_error'
|
3
|
+
require_relative '../helper'
|
4
|
+
require_relative '../module'
|
5
|
+
|
6
|
+
module PantographCore
|
7
|
+
class ConfigItem
|
8
|
+
# [Symbol] the key which is used as command parameters or key in the pantograph tools
|
9
|
+
attr_accessor :key
|
10
|
+
|
11
|
+
# [String] the name of the environment variable, which is only used if no other values were found
|
12
|
+
attr_accessor :env_name
|
13
|
+
|
14
|
+
# [String] A description shown to the user
|
15
|
+
attr_accessor :description
|
16
|
+
|
17
|
+
# [String] A string of length 1 which is used for the command parameters (e.g. -f)
|
18
|
+
attr_accessor :short_option
|
19
|
+
|
20
|
+
# the value which is used if there was no given values and no environment values
|
21
|
+
attr_accessor :default_value
|
22
|
+
|
23
|
+
# [Boolean] Set if the default value is generated dynamically
|
24
|
+
attr_accessor :default_value_dynamic
|
25
|
+
|
26
|
+
# the value which is used during Swift code generation
|
27
|
+
# if the default_value reads from ENV or a file, or from local credentials, we need
|
28
|
+
# to provide a different default or it might be included in our autogenerated Swift
|
29
|
+
# as a built-in default for the pantograph gem. This is because when we generate the
|
30
|
+
# Swift API at deployment time, it fetches the default_value from the config_items
|
31
|
+
attr_accessor :code_gen_default_value
|
32
|
+
|
33
|
+
# An optional block which is called when a new value is set.
|
34
|
+
# Check value is valid. This could be type checks or if a folder/file exists
|
35
|
+
# You have to raise a specific exception if something goes wrong. Use `user_error!` for the message: UI.user_error!("your message")
|
36
|
+
attr_accessor :verify_block
|
37
|
+
|
38
|
+
# [Boolean] is false by default. If set to true, also string values will not be asked to the user
|
39
|
+
attr_accessor :optional
|
40
|
+
|
41
|
+
# [Boolean] is false by default. If set to true, type of the parameter will not be validated.
|
42
|
+
attr_accessor :skip_type_validation
|
43
|
+
|
44
|
+
# [Array] array of conflicting option keys(@param key). This allows to resolve conflicts intelligently
|
45
|
+
attr_accessor :conflicting_options
|
46
|
+
|
47
|
+
# An optional block which is called when options conflict happens
|
48
|
+
attr_accessor :conflict_block
|
49
|
+
|
50
|
+
# [String] Set if the option is deprecated. A deprecated option should be optional and is made optional if the parameter isn't set, and fails otherwise
|
51
|
+
attr_accessor :deprecated
|
52
|
+
|
53
|
+
# [Boolean] Set if the variable is sensitive, such as a password or API token, to prevent echoing when prompted for the parameter
|
54
|
+
# If a default value exists, it won't be used during code generation as default values can read from environment variables.
|
55
|
+
attr_accessor :sensitive
|
56
|
+
|
57
|
+
# [Boolean] Set if the default value should never be used during code generation for Swift
|
58
|
+
# We generate the Swift API at deployment time, and if there is a value that should never be
|
59
|
+
# included in the Pantograph.swift or other autogenerated classes, we need to strip it out.
|
60
|
+
# This includes things like API keys that could be read from ENV[]
|
61
|
+
attr_accessor :code_gen_sensitive
|
62
|
+
|
63
|
+
# [Boolean] Set if the variable is to be converted to a shell-escaped String when provided as a Hash or Array
|
64
|
+
# Allows items expected to be strings used in shell arguments to be alternatively provided as a Hash or Array for better readability and auto-escaped for us.
|
65
|
+
attr_accessor :allow_shell_conversion
|
66
|
+
|
67
|
+
# [Boolean] Set if the variable can be used from shell
|
68
|
+
attr_accessor :display_in_shell
|
69
|
+
|
70
|
+
# Creates a new option
|
71
|
+
# @param key (Symbol) the key which is used as command parameters or key in the pantograph tools
|
72
|
+
# @param env_name (String) the name of the environment variable, which is only used if no other values were found
|
73
|
+
# @param description (String) A description shown to the user
|
74
|
+
# @param short_option (String) A string of length 1 which is used for the command parameters (e.g. -f)
|
75
|
+
# @param default_value the value which is used if there was no given values and no environment values
|
76
|
+
# @param default_value_dynamic (Boolean) Set if the default value is generated dynamically
|
77
|
+
# @param verify_block an optional block which is called when a new value is set.
|
78
|
+
# Check value is valid. This could be type checks or if a folder/file exists
|
79
|
+
# You have to raise a specific exception if something goes wrong. Append .red after the string
|
80
|
+
# @param is_string *DEPRECATED: Use `type` instead* (Boolean) is that parameter a string? Defaults to true. If it's true, the type string will be verified.
|
81
|
+
# @param type (Class) the data type of this config item. Takes precedence over `is_string`. Use `:shell_string` to allow types `String`, `Hash` and `Array` that will be converted to shell-escaped strings
|
82
|
+
# @param skip_type_validation (Boolean) is false by default. If set to true, type of the parameter will not be validated.
|
83
|
+
# @param optional (Boolean) is false by default. If set to true, also string values will not be asked to the user
|
84
|
+
# @param conflicting_options ([]) array of conflicting option keys(@param key). This allows to resolve conflicts intelligently
|
85
|
+
# @param conflict_block an optional block which is called when options conflict happens
|
86
|
+
# @param deprecated (Boolean|String) Set if the option is deprecated. A deprecated option should be optional and is made optional if the parameter isn't set, and fails otherwise
|
87
|
+
# @param sensitive (Boolean) Set if the variable is sensitive, such as a password or API token, to prevent echoing when prompted for the parameter
|
88
|
+
# @param display_in_shell (Boolean) Set if the variable can be used from shell
|
89
|
+
# rubocop:disable Metrics/ParameterLists
|
90
|
+
def initialize(key: nil,
|
91
|
+
env_name: nil,
|
92
|
+
description: nil,
|
93
|
+
short_option: nil,
|
94
|
+
default_value: nil,
|
95
|
+
default_value_dynamic: false,
|
96
|
+
verify_block: nil,
|
97
|
+
is_string: true,
|
98
|
+
type: nil,
|
99
|
+
skip_type_validation: false,
|
100
|
+
optional: nil,
|
101
|
+
conflicting_options: nil,
|
102
|
+
conflict_block: nil,
|
103
|
+
deprecated: nil,
|
104
|
+
sensitive: nil,
|
105
|
+
code_gen_sensitive: false,
|
106
|
+
code_gen_default_value: nil,
|
107
|
+
display_in_shell: true)
|
108
|
+
UI.user_error!("key must be a symbol") unless key.kind_of?(Symbol)
|
109
|
+
UI.user_error!("env_name must be a String") unless (env_name || '').kind_of?(String)
|
110
|
+
|
111
|
+
if short_option
|
112
|
+
UI.user_error!("short_option for key :#{key} must of type String") unless short_option.kind_of?(String)
|
113
|
+
UI.user_error!("short_option for key :#{key} must be a string of length 1") unless short_option.delete('-').length == 1
|
114
|
+
end
|
115
|
+
|
116
|
+
if description
|
117
|
+
UI.user_error!("Do not let descriptions end with a '.', since it's used for user inputs as well for key :#{key}") if description[-1] == '.'
|
118
|
+
end
|
119
|
+
|
120
|
+
if conflicting_options
|
121
|
+
conflicting_options.each do |conflicting_option_key|
|
122
|
+
UI.user_error!("Conflicting option key must be a symbol") unless conflicting_option_key.kind_of?(Symbol)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if deprecated
|
127
|
+
# deprecated options are automatically optional
|
128
|
+
optional = true if optional.nil?
|
129
|
+
UI.crash!("Deprecated option must be optional") unless optional
|
130
|
+
|
131
|
+
# deprecated options are marked deprecated in their description
|
132
|
+
description = deprecated_description(description, deprecated)
|
133
|
+
end
|
134
|
+
|
135
|
+
optional = false if optional.nil?
|
136
|
+
sensitive = false if sensitive.nil?
|
137
|
+
|
138
|
+
@key = key
|
139
|
+
@env_name = env_name
|
140
|
+
@description = description
|
141
|
+
@short_option = short_option
|
142
|
+
@default_value = default_value
|
143
|
+
@default_value_dynamic = default_value_dynamic
|
144
|
+
@verify_block = verify_block
|
145
|
+
@is_string = is_string
|
146
|
+
@data_type = type
|
147
|
+
@data_type = String if type == :shell_string
|
148
|
+
@optional = optional
|
149
|
+
@conflicting_options = conflicting_options
|
150
|
+
@conflict_block = conflict_block
|
151
|
+
@deprecated = deprecated
|
152
|
+
@sensitive = sensitive
|
153
|
+
@code_gen_sensitive = code_gen_sensitive || sensitive
|
154
|
+
@allow_shell_conversion = (type == :shell_string)
|
155
|
+
@display_in_shell = display_in_shell
|
156
|
+
@skip_type_validation = skip_type_validation # sometimes we allow multiple types which causes type validation failures, e.g.: export_options in gym
|
157
|
+
|
158
|
+
@code_gen_default_value = code_gen_default_value
|
159
|
+
|
160
|
+
update_code_gen_default_value_if_able!
|
161
|
+
end
|
162
|
+
# rubocop:enable Metrics/ParameterLists
|
163
|
+
|
164
|
+
# if code_gen_default_value is nil, use the default value if it isn't a `code_gen_sensitive` value
|
165
|
+
def update_code_gen_default_value_if_able!
|
166
|
+
# we don't support default values for procs
|
167
|
+
if @data_type == :string_callback
|
168
|
+
@code_gen_default_value = nil
|
169
|
+
return
|
170
|
+
end
|
171
|
+
|
172
|
+
if @code_gen_default_value.nil?
|
173
|
+
unless @code_gen_sensitive
|
174
|
+
|
175
|
+
@code_gen_default_value = @default_value
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def verify!(value)
|
181
|
+
valid?(value)
|
182
|
+
end
|
183
|
+
|
184
|
+
def ensure_generic_type_passes_validation(value)
|
185
|
+
if @skip_type_validation
|
186
|
+
return
|
187
|
+
end
|
188
|
+
|
189
|
+
if data_type != :string_callback && data_type && !value.kind_of?(data_type)
|
190
|
+
UI.user_error!("'#{self.key}' value must be a #{data_type}! Found #{value.class} instead.")
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def ensure_boolean_type_passes_validation(value)
|
195
|
+
if @skip_type_validation
|
196
|
+
return
|
197
|
+
end
|
198
|
+
|
199
|
+
# We need to explicitly test against Pantograph::Boolean, TrueClass/FalseClass
|
200
|
+
if value.class != FalseClass && value.class != TrueClass
|
201
|
+
UI.user_error!("'#{self.key}' value must be either `true` or `false`! Found #{value.class} instead.")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Make sure, the value is valid (based on the verify block)
|
206
|
+
# Raises an exception if the value is invalid
|
207
|
+
def valid?(value)
|
208
|
+
# we also allow nil values, which do not have to be verified.
|
209
|
+
return true if value.nil?
|
210
|
+
|
211
|
+
# Verify that value is the type that we're expecting, if we are expecting a type
|
212
|
+
if data_type == Pantograph::Boolean
|
213
|
+
ensure_boolean_type_passes_validation(value)
|
214
|
+
else
|
215
|
+
ensure_generic_type_passes_validation(value)
|
216
|
+
end
|
217
|
+
|
218
|
+
if @verify_block
|
219
|
+
begin
|
220
|
+
@verify_block.call(value)
|
221
|
+
rescue => ex
|
222
|
+
UI.error("Error setting value '#{value}' for option '#{@key}'")
|
223
|
+
raise Interface::PantographError.new, ex.to_s
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
true
|
228
|
+
end
|
229
|
+
|
230
|
+
# Returns an updated value type (if necessary)
|
231
|
+
def auto_convert_value(value)
|
232
|
+
return nil if value.nil?
|
233
|
+
|
234
|
+
if data_type == Array
|
235
|
+
return value.split(',') if value.kind_of?(String)
|
236
|
+
elsif data_type == Integer
|
237
|
+
return value.to_i if value.to_i.to_s == value.to_s
|
238
|
+
elsif data_type == Float
|
239
|
+
return value.to_f if value.to_f.to_s == value.to_s
|
240
|
+
elsif allow_shell_conversion
|
241
|
+
return value.shelljoin if value.kind_of?(Array)
|
242
|
+
return value.map { |k, v| "#{k.to_s.shellescape}=#{v.shellescape}" }.join(' ') if value.kind_of?(Hash)
|
243
|
+
elsif data_type != String
|
244
|
+
# Special treatment if the user specified true, false or YES, NO
|
245
|
+
# There is no boolean type, so we just do it here
|
246
|
+
if %w(YES yes true TRUE).include?(value)
|
247
|
+
return true
|
248
|
+
elsif %w(NO no false FALSE).include?(value)
|
249
|
+
return false
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
return value # fallback to not doing anything
|
254
|
+
end
|
255
|
+
|
256
|
+
# Determines the defined data type of this ConfigItem
|
257
|
+
def data_type
|
258
|
+
if @data_type.kind_of?(Symbol)
|
259
|
+
nil
|
260
|
+
elsif @data_type
|
261
|
+
@data_type
|
262
|
+
else
|
263
|
+
(@is_string ? String : nil)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Replaces the attr_accessor, but maintains the same interface
|
268
|
+
def string?
|
269
|
+
data_type == String
|
270
|
+
end
|
271
|
+
|
272
|
+
# it's preferred to use self.string? In most cases, except in commander_generator.rb, cause... reasons
|
273
|
+
def is_string
|
274
|
+
return @is_string
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_s
|
278
|
+
[@key, @description].join(": ")
|
279
|
+
end
|
280
|
+
|
281
|
+
def deprecated_description(initial_description, deprecated)
|
282
|
+
has_description = !initial_description.to_s.empty?
|
283
|
+
|
284
|
+
description = "**DEPRECATED!**"
|
285
|
+
|
286
|
+
if deprecated.kind_of?(String)
|
287
|
+
description << " #{deprecated}"
|
288
|
+
description << " -" if has_description
|
289
|
+
end
|
290
|
+
|
291
|
+
description << " #{initial_description}" if has_description
|
292
|
+
|
293
|
+
description
|
294
|
+
end
|
295
|
+
|
296
|
+
def doc_default_value
|
297
|
+
return "[*](#parameters-legend-dynamic)" if self.default_value_dynamic
|
298
|
+
return "" if self.default_value.nil?
|
299
|
+
return "`''`" if self.default_value.instance_of?(String) && self.default_value.empty?
|
300
|
+
return "`:#{self.default_value}`" if self.default_value.instance_of?(Symbol)
|
301
|
+
|
302
|
+
"`#{self.default_value}`"
|
303
|
+
end
|
304
|
+
|
305
|
+
def help_default_value
|
306
|
+
return "#{self.default_value} *".strip if self.default_value_dynamic
|
307
|
+
return "" if self.default_value.nil?
|
308
|
+
return "''" if self.default_value.instance_of?(String) && self.default_value.empty?
|
309
|
+
return ":#{self.default_value}" if self.default_value.instance_of?(Symbol)
|
310
|
+
|
311
|
+
self.default_value
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require_relative '../globals'
|
3
|
+
require_relative 'config_item'
|
4
|
+
require_relative 'commander_generator'
|
5
|
+
require_relative 'configuration_file'
|
6
|
+
|
7
|
+
module PantographCore
|
8
|
+
class Configuration
|
9
|
+
attr_accessor :available_options
|
10
|
+
|
11
|
+
attr_accessor :values
|
12
|
+
|
13
|
+
# @return [Array] An array of symbols which are all available keys
|
14
|
+
attr_reader :all_keys
|
15
|
+
|
16
|
+
# @return [String] The name of the configuration file (not the path). Optional!
|
17
|
+
attr_accessor :config_file_name
|
18
|
+
|
19
|
+
# @return [Hash] Options that were set from a config file using load_configuration_file. Optional!
|
20
|
+
attr_accessor :config_file_options
|
21
|
+
|
22
|
+
def self.create(available_options, values)
|
23
|
+
UI.user_error!("values parameter must be a hash") unless values.kind_of?(Hash)
|
24
|
+
v = values.dup
|
25
|
+
v.each do |key, val|
|
26
|
+
v[key] = val.dup if val.kind_of?(String) # this is necessary when fetching a value from an environment variable
|
27
|
+
end
|
28
|
+
|
29
|
+
if v.kind_of?(Hash) && available_options.kind_of?(Array) # we only want to deal with the new configuration system
|
30
|
+
# Now see if --verbose would be a valid input
|
31
|
+
# If not, it might be because it's an action and not a tool
|
32
|
+
unless available_options.find { |a| a.kind_of?(ConfigItem) && a.key == :verbose }
|
33
|
+
v.delete(:verbose) # as this is being processed by commander
|
34
|
+
end
|
35
|
+
end
|
36
|
+
Configuration.new(available_options, v)
|
37
|
+
end
|
38
|
+
|
39
|
+
#####################################################
|
40
|
+
# @!group Setting up the configuration
|
41
|
+
#####################################################
|
42
|
+
|
43
|
+
# collect sensitive strings
|
44
|
+
def self.sensitive_strings
|
45
|
+
@sensitive_strings ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(available_options, values)
|
49
|
+
self.available_options = available_options || []
|
50
|
+
self.values = values || {}
|
51
|
+
self.config_file_options = {}
|
52
|
+
|
53
|
+
# used for pushing and popping values to provide nesting configuration contexts
|
54
|
+
@values_stack = []
|
55
|
+
|
56
|
+
# if we are in captured output mode - keep a array of sensitive option values
|
57
|
+
# those will be later - replaced by ####
|
58
|
+
if PantographCore::Globals.capture_output?
|
59
|
+
available_options.each do |element|
|
60
|
+
next unless element.sensitive
|
61
|
+
self.class.sensitive_strings << values[element.key]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
verify_input_types
|
66
|
+
verify_value_exists
|
67
|
+
verify_no_duplicates
|
68
|
+
verify_conflicts
|
69
|
+
verify_default_value_matches_verify_block
|
70
|
+
end
|
71
|
+
|
72
|
+
def verify_input_types
|
73
|
+
UI.user_error!("available_options parameter must be an array of ConfigItems but is #{@available_options.class}") unless @available_options.kind_of?(Array)
|
74
|
+
@available_options.each do |item|
|
75
|
+
UI.user_error!("available_options parameter must be an array of ConfigItems. Found #{item.class}.") unless item.kind_of?(ConfigItem)
|
76
|
+
end
|
77
|
+
UI.user_error!("values parameter must be a hash") unless @values.kind_of?(Hash)
|
78
|
+
end
|
79
|
+
|
80
|
+
def verify_value_exists
|
81
|
+
# Make sure the given value keys exist
|
82
|
+
@values.each do |key, value|
|
83
|
+
next if key == :trace # special treatment
|
84
|
+
option = self.verify_options_key!(key)
|
85
|
+
@values[key] = option.auto_convert_value(value)
|
86
|
+
UI.deprecated("Using deprecated option: '--#{key}' (#{option.deprecated})") if option.deprecated
|
87
|
+
option.verify!(@values[key]) # Call the verify block for it too
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def verify_no_duplicates
|
92
|
+
# Make sure a key was not used multiple times
|
93
|
+
@available_options.each do |current|
|
94
|
+
count = @available_options.count { |option| option.key == current.key }
|
95
|
+
UI.user_error!("Multiple entries for configuration key '#{current.key}' found!") if count > 1
|
96
|
+
|
97
|
+
unless current.short_option.to_s.empty?
|
98
|
+
count = @available_options.count { |option| option.short_option == current.short_option }
|
99
|
+
UI.user_error!("Multiple entries for short_option '#{current.short_option}' found!") if count > 1
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def verify_conflicts
|
105
|
+
option_keys = @values.keys
|
106
|
+
|
107
|
+
option_keys.each do |current|
|
108
|
+
index = @available_options.find_index { |item| item.key == current }
|
109
|
+
current = @available_options[index]
|
110
|
+
|
111
|
+
# ignore conflicts because option value is nil
|
112
|
+
next if @values[current.key].nil?
|
113
|
+
|
114
|
+
next if current.conflicting_options.nil?
|
115
|
+
|
116
|
+
conflicts = current.conflicting_options & option_keys
|
117
|
+
next if conflicts.nil?
|
118
|
+
|
119
|
+
conflicts.each do |conflicting_option_key|
|
120
|
+
index = @available_options.find_index { |item| item.key == conflicting_option_key }
|
121
|
+
conflicting_option = @available_options[index]
|
122
|
+
|
123
|
+
# ignore conflicts because because value of conflict option is nil
|
124
|
+
next if @values[conflicting_option.key].nil?
|
125
|
+
|
126
|
+
if current.conflict_block
|
127
|
+
begin
|
128
|
+
current.conflict_block.call(conflicting_option)
|
129
|
+
rescue => ex
|
130
|
+
UI.error("Error resolving conflict between options: '#{current.key}' and '#{conflicting_option.key}'")
|
131
|
+
raise ex
|
132
|
+
end
|
133
|
+
else
|
134
|
+
UI.user_error!("Unresolved conflict between options: '#{current.key}' and '#{conflicting_option.key}'")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Verifies the default value is also valid
|
141
|
+
def verify_default_value_matches_verify_block
|
142
|
+
@available_options.each do |item|
|
143
|
+
next unless item.verify_block && item.default_value
|
144
|
+
|
145
|
+
begin
|
146
|
+
unless @values[item.key] # this is important to not verify if there already is a value there
|
147
|
+
item.verify_block.call(item.default_value)
|
148
|
+
end
|
149
|
+
rescue => ex
|
150
|
+
UI.error(ex)
|
151
|
+
UI.user_error!("Invalid default value for #{item.key}, doesn't match verify_block")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# This method takes care of parsing and using the configuration file as values
|
157
|
+
# Call this once you know where the config file might be located
|
158
|
+
# Take a look at how `gym` uses this method
|
159
|
+
#
|
160
|
+
# @param config_file_name [String] The name of the configuration file to use (optional)
|
161
|
+
# @param block_for_missing [Block] A ruby block that is called when there is an unknown method
|
162
|
+
# in the configuration file
|
163
|
+
def load_configuration_file(config_file_name = nil, block_for_missing = nil, skip_printing_values = false)
|
164
|
+
return unless config_file_name
|
165
|
+
|
166
|
+
self.config_file_name = config_file_name
|
167
|
+
|
168
|
+
path = PantographCore::Configuration.find_configuration_file_path(config_file_name: config_file_name)
|
169
|
+
return if path.nil?
|
170
|
+
|
171
|
+
begin
|
172
|
+
configuration_file = ConfigurationFile.new(self, path, block_for_missing, skip_printing_values)
|
173
|
+
options = configuration_file.options
|
174
|
+
rescue PantographCore::ConfigurationFile::ExceptionWhileParsingError => e
|
175
|
+
options = e.recovered_options
|
176
|
+
wrapped_exception = e.wrapped_exception
|
177
|
+
end
|
178
|
+
|
179
|
+
# Make sure all the values set in the config file pass verification
|
180
|
+
options.each do |key, val|
|
181
|
+
option = self.verify_options_key!(key)
|
182
|
+
option.verify!(val)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Merge the new options into the old ones, keeping all previously set keys
|
186
|
+
self.config_file_options = options.merge(self.config_file_options)
|
187
|
+
|
188
|
+
verify_conflicts # important, since user can set conflicting options in configuration file
|
189
|
+
|
190
|
+
# Now that everything is verified, re-raise an exception that was raised in the config file
|
191
|
+
raise wrapped_exception unless wrapped_exception.nil?
|
192
|
+
|
193
|
+
configuration_file
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.find_configuration_file_path(config_file_name: nil)
|
197
|
+
paths = []
|
198
|
+
paths += Dir["./pantograph/#{config_file_name}"]
|
199
|
+
paths += Dir["./.pantograph/#{config_file_name}"]
|
200
|
+
paths += Dir["./#{config_file_name}"]
|
201
|
+
paths += Dir["./pantograph_core/spec/fixtures/#{config_file_name}"] if Helper.test?
|
202
|
+
return nil if paths.count == 0
|
203
|
+
return paths.first
|
204
|
+
end
|
205
|
+
|
206
|
+
#####################################################
|
207
|
+
# @!group Actually using the class
|
208
|
+
#####################################################
|
209
|
+
|
210
|
+
# Returns the value for a certain key. pantograph_core tries to fetch the value from different sources
|
211
|
+
# if 'ask' is true and the value is not present, the user will be prompted to provide a value
|
212
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
213
|
+
def fetch(key, ask: true)
|
214
|
+
UI.crash!("Key '#{key}' must be a symbol. Example :app_id.") unless key.kind_of?(Symbol)
|
215
|
+
|
216
|
+
option = verify_options_key!(key)
|
217
|
+
|
218
|
+
# Same order as https://docs.pantograph.tools/advanced/#priorities-of-parameters-and-options
|
219
|
+
value = if @values.key?(key) && !@values[key].nil?
|
220
|
+
@values[key]
|
221
|
+
elsif option.env_name && !ENV[option.env_name].nil?
|
222
|
+
# verify! before using (see https://github.com/pantograph/pantograph/issues/14449)
|
223
|
+
ENV[option.env_name].dup if option.verify!(option.auto_convert_value(ENV[option.env_name]))
|
224
|
+
elsif self.config_file_options.key?(key)
|
225
|
+
self.config_file_options[key]
|
226
|
+
else
|
227
|
+
option.default_value
|
228
|
+
end
|
229
|
+
|
230
|
+
value = option.auto_convert_value(value)
|
231
|
+
value = nil if value.nil? && !option.string? # by default boolean flags are false
|
232
|
+
return value unless value.nil? && !option.optional && ask
|
233
|
+
|
234
|
+
# fallback to asking
|
235
|
+
if Helper.test? || !UI.interactive?
|
236
|
+
# Since we don't want to be asked on tests, we'll just call the verify block with no value
|
237
|
+
# to raise the exception that is shown when the user passes an invalid value
|
238
|
+
set(key, '')
|
239
|
+
# If this didn't raise an exception, just raise a default one
|
240
|
+
UI.user_error!("No value found for '#{key}'")
|
241
|
+
end
|
242
|
+
|
243
|
+
while value.nil?
|
244
|
+
UI.important("To not be asked about this value, you can specify it using '#{option.key}'") if ENV["PANTOGRAPH_ONBOARDING_IN_PROCESS"].to_s.length == 0
|
245
|
+
value = option.sensitive ? UI.password("#{option.description}: ") : UI.input("#{option.description}: ")
|
246
|
+
# Also store this value to use it from now on
|
247
|
+
begin
|
248
|
+
set(key, value)
|
249
|
+
rescue => ex
|
250
|
+
puts(ex)
|
251
|
+
value = nil
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# It's very, very important to use the self[:my_key] notation
|
256
|
+
# as this will make sure to use the `fetch` method
|
257
|
+
# that is responsible for auto converting the values into the right
|
258
|
+
# data type
|
259
|
+
# Found out via https://github.com/pantograph/pantograph/issues/11243
|
260
|
+
return self[key]
|
261
|
+
end
|
262
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
263
|
+
|
264
|
+
# Overwrites or sets a new value for a given key
|
265
|
+
# @param key [Symbol] Must be a symbol
|
266
|
+
def set(key, value)
|
267
|
+
UI.crash!("Key '#{key}' must be a symbol. Example :#{key}.") unless key.kind_of?(Symbol)
|
268
|
+
option = option_for_key(key)
|
269
|
+
|
270
|
+
unless option
|
271
|
+
UI.user_error!("Could not find option '#{key}' in the list of available options: #{@available_options.collect(&:key).join(', ')}")
|
272
|
+
end
|
273
|
+
|
274
|
+
option.verify!(value)
|
275
|
+
|
276
|
+
@values[key] = value
|
277
|
+
true
|
278
|
+
end
|
279
|
+
|
280
|
+
# see fetch
|
281
|
+
def values(ask: true)
|
282
|
+
# As the user accesses all values, we need to iterate through them to receive all the values
|
283
|
+
@available_options.each do |option|
|
284
|
+
@values[option.key] = fetch(option.key, ask: ask) unless @values[option.key]
|
285
|
+
end
|
286
|
+
@values
|
287
|
+
end
|
288
|
+
|
289
|
+
# Direct access to the values, without iterating through all items
|
290
|
+
def _values
|
291
|
+
@values
|
292
|
+
end
|
293
|
+
|
294
|
+
# Clears away any current configuration values by pushing them onto a stack.
|
295
|
+
# Values set after calling push_values! will be merged with the previous
|
296
|
+
# values after calling pop_values!
|
297
|
+
#
|
298
|
+
# see: pop_values!
|
299
|
+
def push_values!
|
300
|
+
@values_stack.push(@values)
|
301
|
+
@values = {}
|
302
|
+
end
|
303
|
+
|
304
|
+
# Restores a previous set of configuration values by merging any current
|
305
|
+
# values on top of them
|
306
|
+
#
|
307
|
+
# see: push_values!
|
308
|
+
def pop_values!
|
309
|
+
return if @values_stack.empty?
|
310
|
+
@values = @values_stack.pop.merge(@values)
|
311
|
+
end
|
312
|
+
|
313
|
+
def all_keys
|
314
|
+
@available_options.collect(&:key)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Returns the config_item object for a given key
|
318
|
+
def option_for_key(key)
|
319
|
+
@available_options.find { |o| o.key == key }
|
320
|
+
end
|
321
|
+
|
322
|
+
# Aliases `[key]` to `fetch(key)` because Ruby can do it.
|
323
|
+
alias [] fetch
|
324
|
+
alias []= set
|
325
|
+
|
326
|
+
def verify_options_key!(key)
|
327
|
+
option = option_for_key(key)
|
328
|
+
UI.user_error!("Could not find option '#{key}' in the list of available options: #{@available_options.collect(&:key).join(', ')}") unless option
|
329
|
+
option
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|