pantograph 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,50 @@
|
|
1
|
+
module Pantograph
|
2
|
+
module Helper
|
3
|
+
class DotenvHelper
|
4
|
+
# @param env_cl_param [String] an optional list of dotenv environment names separated by commas, without space
|
5
|
+
def self.load_dot_env(env_cl_param)
|
6
|
+
base_path = find_dotenv_directory
|
7
|
+
|
8
|
+
return unless base_path
|
9
|
+
|
10
|
+
load_dot_envs_from(env_cl_param, base_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
# finds the first directory of [pantograph, its parent] containing dotenv files
|
14
|
+
def self.find_dotenv_directory
|
15
|
+
path = PantographCore::PantographFolder.path
|
16
|
+
search_paths = [path]
|
17
|
+
search_paths << path + "/.." unless path.nil?
|
18
|
+
search_paths.compact!
|
19
|
+
search_paths.find do |dir|
|
20
|
+
Dir.glob(File.join(dir, '*.env*'), File::FNM_DOTMATCH).count > 0
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# loads the dotenvs. First the .env and .env.default and
|
25
|
+
# then override with all speficied extra environments
|
26
|
+
def self.load_dot_envs_from(env_cl_param, base_path)
|
27
|
+
require 'dotenv'
|
28
|
+
|
29
|
+
# Making sure the default '.env' and '.env.default' get loaded
|
30
|
+
env_file = File.join(base_path, '.env')
|
31
|
+
env_default_file = File.join(base_path, '.env.default')
|
32
|
+
Dotenv.load(env_file, env_default_file)
|
33
|
+
|
34
|
+
return unless env_cl_param
|
35
|
+
|
36
|
+
Pantograph::Actions.lane_context[Pantograph::Actions::SharedValues::ENVIRONMENT] = env_cl_param
|
37
|
+
|
38
|
+
# multiple envs?
|
39
|
+
envs = env_cl_param.split(",")
|
40
|
+
|
41
|
+
# Loads .env file for the environment(s) passed in through options
|
42
|
+
envs.each do |env|
|
43
|
+
env_file = File.join(base_path, ".env.#{env}")
|
44
|
+
UI.success("Loading from '#{env_file}'")
|
45
|
+
Dotenv.overload(env_file)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Pantograph
|
2
|
+
module Actions
|
3
|
+
# will make sure a gem is installed. If it's not an appropriate error message is shown
|
4
|
+
# this will *not* 'require' the gem
|
5
|
+
def self.verify_gem!(gem_name)
|
6
|
+
begin
|
7
|
+
PantographRequire.install_gem_if_needed(gem_name: gem_name, require_gem: false)
|
8
|
+
# We don't import this by default, as it's not always the same
|
9
|
+
# also e.g. cocoapods is just required and not imported
|
10
|
+
rescue Gem::LoadError
|
11
|
+
UI.error("Could not find gem '#{gem_name}'")
|
12
|
+
UI.error("")
|
13
|
+
UI.error("If you installed pantograph using `gem install pantograph` run")
|
14
|
+
UI.command("gem install #{gem_name}")
|
15
|
+
UI.error("to install the missing gem")
|
16
|
+
UI.error("")
|
17
|
+
UI.error("If you use a Gemfile add this to your Gemfile:")
|
18
|
+
UI.important(" gem '#{gem_name}'")
|
19
|
+
UI.error("and run `bundle install`")
|
20
|
+
|
21
|
+
UI.user_error!("You have to install the `#{gem_name}` gem on this machine") unless Helper.test?
|
22
|
+
end
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Pantograph
|
2
|
+
module Actions
|
3
|
+
GIT_MERGE_COMMIT_FILTERING_OPTIONS = [:include_merges, :exclude_merges, :only_include_merges].freeze
|
4
|
+
|
5
|
+
def self.git_log_between(pretty_format, from, to, merge_commit_filtering, date_format = nil, ancestry_path)
|
6
|
+
command = %w(git log)
|
7
|
+
command << "--pretty=#{pretty_format}"
|
8
|
+
command << "--date=#{date_format}" if date_format
|
9
|
+
command << '--ancestry-path' if ancestry_path
|
10
|
+
command << "#{from}...#{to}"
|
11
|
+
command << git_log_merge_commit_filtering_option(merge_commit_filtering)
|
12
|
+
# "*command" syntax expands "command" array into variable arguments, which
|
13
|
+
# will then be individually shell-escaped by Actions.sh.
|
14
|
+
Actions.sh(*command.compact, log: false).chomp
|
15
|
+
rescue
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.git_log_last_commits(pretty_format, commit_count, merge_commit_filtering, date_format = nil, ancestry_path)
|
20
|
+
command = %w(git log)
|
21
|
+
command << "--pretty=#{pretty_format}"
|
22
|
+
command << "--date=#{date_format}" if date_format
|
23
|
+
command << '--ancestry-path' if ancestry_path
|
24
|
+
command << '-n' << commit_count.to_s
|
25
|
+
command << git_log_merge_commit_filtering_option(merge_commit_filtering)
|
26
|
+
Actions.sh(*command.compact, log: false).chomp
|
27
|
+
rescue
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.last_git_tag_hash(tag_match_pattern = nil)
|
32
|
+
tag_pattern_param = tag_match_pattern ? "=#{tag_match_pattern}" : ''
|
33
|
+
Actions.sh('git', 'rev-list', "--tags#{tag_pattern_param}", '--max-count=1').chomp
|
34
|
+
rescue
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.last_git_tag_name(match_lightweight = true, tag_match_pattern = nil)
|
39
|
+
hash = last_git_tag_hash(tag_match_pattern)
|
40
|
+
# If hash is nil (command fails), "git describe" command below will still
|
41
|
+
# run and provide some output, although it's definitely not going to be
|
42
|
+
# anything reasonably expected. Bail out early.
|
43
|
+
return unless hash
|
44
|
+
|
45
|
+
command = %w(git describe)
|
46
|
+
command << '--tags' if match_lightweight
|
47
|
+
command << hash
|
48
|
+
Actions.sh(*command.compact, log: false).chomp
|
49
|
+
rescue
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.last_git_commit_dict
|
54
|
+
return nil if last_git_commit_formatted_with('%an').nil?
|
55
|
+
|
56
|
+
{
|
57
|
+
author: last_git_commit_formatted_with('%an'),
|
58
|
+
author_email: last_git_commit_formatted_with('%ae'),
|
59
|
+
message: last_git_commit_formatted_with('%B'),
|
60
|
+
commit_hash: last_git_commit_formatted_with('%H'),
|
61
|
+
abbreviated_commit_hash: last_git_commit_formatted_with('%h')
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Gets the last git commit information formatted into a String by the provided
|
66
|
+
# pretty format String. See the git-log documentation for valid format placeholders
|
67
|
+
def self.last_git_commit_formatted_with(pretty_format, date_format = nil)
|
68
|
+
command = %w(git log -1)
|
69
|
+
command << "--pretty=#{pretty_format}"
|
70
|
+
command << "--date=#{date_format}" if date_format
|
71
|
+
Actions.sh(*command.compact, log: false).chomp
|
72
|
+
rescue
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# @deprecated Use <tt>git_author_email</tt> instead
|
77
|
+
# Get the author email of the last git commit
|
78
|
+
# <b>DEPRECATED:</b> Use <tt>git_author_email</tt> instead.
|
79
|
+
def self.git_author
|
80
|
+
UI.deprecated('`git_author` is deprecated. Please use `git_author_email` instead.')
|
81
|
+
git_author_email
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get the author email of the last git commit
|
85
|
+
def self.git_author_email
|
86
|
+
s = last_git_commit_formatted_with('%ae')
|
87
|
+
return s if s.to_s.length > 0
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the unwrapped subject and body of the last commit
|
92
|
+
# <b>DEPRECATED:</b> Use <tt>last_git_commit_message</tt> instead.
|
93
|
+
def self.last_git_commit
|
94
|
+
UI.important('`last_git_commit` is deprecated. Please use `last_git_commit_message` instead.')
|
95
|
+
last_git_commit_message
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns the unwrapped subject and body of the last commit
|
99
|
+
def self.last_git_commit_message
|
100
|
+
s = (last_git_commit_formatted_with('%B') || "").strip
|
101
|
+
return s if s.to_s.length > 0
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get the hash of the last commit
|
106
|
+
def self.last_git_commit_hash(short)
|
107
|
+
format_specifier = short ? '%h' : '%H'
|
108
|
+
string = last_git_commit_formatted_with(format_specifier).to_s
|
109
|
+
return string unless string.empty?
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the current git branch - can be replaced using the environment variable `GIT_BRANCH`
|
114
|
+
def self.git_branch
|
115
|
+
return ENV['GIT_BRANCH'] if ENV['GIT_BRANCH'].to_s.length > 0 # set by Jenkins
|
116
|
+
s = Actions.sh("git rev-parse --abbrev-ref HEAD", log: false).chomp
|
117
|
+
return s.to_s.strip if s.to_s.length > 0
|
118
|
+
nil
|
119
|
+
rescue
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
private_class_method
|
124
|
+
def self.git_log_merge_commit_filtering_option(merge_commit_filtering)
|
125
|
+
case merge_commit_filtering
|
126
|
+
when :exclude_merges
|
127
|
+
"--no-merges"
|
128
|
+
when :only_include_merges
|
129
|
+
"--merges"
|
130
|
+
when :include_merges
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Pantograph
|
2
|
+
module Helper
|
3
|
+
class GradleTask
|
4
|
+
attr_accessor :title
|
5
|
+
|
6
|
+
attr_accessor :description
|
7
|
+
|
8
|
+
def initialize(title: nil, description: nil)
|
9
|
+
self.title = title
|
10
|
+
self.description = description
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class GradleHelper
|
15
|
+
# Path to the gradle script
|
16
|
+
attr_accessor :gradle_path
|
17
|
+
|
18
|
+
# Read-only path to the shell-escaped gradle script, suitable for use in shell commands
|
19
|
+
attr_reader :escaped_gradle_path
|
20
|
+
|
21
|
+
# All the available tasks
|
22
|
+
attr_accessor :tasks
|
23
|
+
|
24
|
+
def initialize(gradle_path: nil)
|
25
|
+
self.gradle_path = gradle_path
|
26
|
+
end
|
27
|
+
|
28
|
+
# Run a certain action
|
29
|
+
def trigger(task: nil, flags: nil, serial: nil, print_command: true, print_command_output: true)
|
30
|
+
android_serial = (serial != "") ? "ANDROID_SERIAL=#{serial}" : nil
|
31
|
+
command = [android_serial, escaped_gradle_path, task, flags].compact.join(" ")
|
32
|
+
Action.sh(command, print_command: print_command, print_command_output: print_command_output)
|
33
|
+
end
|
34
|
+
|
35
|
+
def task_available?(task)
|
36
|
+
load_all_tasks
|
37
|
+
return tasks.collect(&:title).include?(task)
|
38
|
+
end
|
39
|
+
|
40
|
+
def gradle_path=(gradle_path)
|
41
|
+
@gradle_path = gradle_path
|
42
|
+
@escaped_gradle_path = gradle_path.shellescape
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def load_all_tasks
|
48
|
+
self.tasks = []
|
49
|
+
|
50
|
+
command = [escaped_gradle_path, "tasks", "--console=plain"].join(" ")
|
51
|
+
output = Action.sh(command, print_command: false, print_command_output: false)
|
52
|
+
output.split("\n").each do |line|
|
53
|
+
if (result = line.match(/(\w+)\s\-\s([\w\s]+)/))
|
54
|
+
self.tasks << GradleTask.new(title: result[1], description: result[2])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
self.tasks
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require "open3"
|
2
|
+
|
3
|
+
module Pantograph
|
4
|
+
module Actions
|
5
|
+
# Execute a shell command
|
6
|
+
# This method will output the string and execute it
|
7
|
+
# Just an alias for sh_no_action
|
8
|
+
# When running this in tests, it will return the actual command instead of executing it
|
9
|
+
# @param log [Boolean] should pantograph print out the executed command
|
10
|
+
# @param error_callback [Block] a callback invoked with the command output if there is a non-zero exit status
|
11
|
+
def self.sh(*command, log: true, error_callback: nil, &b)
|
12
|
+
sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.sh_no_action(*command, log: true, error_callback: nil, &b)
|
16
|
+
sh_control_output(*command, print_command: log, print_command_output: log, error_callback: error_callback, &b)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param command The command to be executed (variadic)
|
20
|
+
# @param print_command [Boolean] Should we print the command that's being executed
|
21
|
+
# @param print_command_output [Boolean] Should we print the command output during execution
|
22
|
+
# @param error_callback [Block] A block that's called if the command exits with a non-zero status
|
23
|
+
# @yield [status, result, cmd] The return status of the command, all output from the command and an equivalent shell command
|
24
|
+
# @yieldparam [Process::Status] status A Process::Status indicating the status of the completed command
|
25
|
+
# @yieldparam [String] result The complete output to stdout and stderr of the completed command
|
26
|
+
# @yieldparam [String] cmd A shell command equivalent to the arguments passed
|
27
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
28
|
+
def self.sh_control_output(*command, print_command: true, print_command_output: true, error_callback: nil)
|
29
|
+
print_command = print_command_output = true if $troubleshoot
|
30
|
+
# Set the encoding first, the user might have set it wrong
|
31
|
+
previous_encoding = [Encoding.default_external, Encoding.default_internal]
|
32
|
+
Encoding.default_external = Encoding::UTF_8
|
33
|
+
Encoding.default_internal = Encoding::UTF_8
|
34
|
+
|
35
|
+
# Workaround to support previous Pantograph syntax.
|
36
|
+
# This has some limitations. For example, it requires the caller to shell escape
|
37
|
+
# everything because of usages like ["ls -la", "/tmp"] instead of ["ls", "-la", "/tmp"].
|
38
|
+
command = [command.first.join(" ")] if command.length == 1 && command.first.kind_of?(Array)
|
39
|
+
|
40
|
+
shell_command = shell_command_from_args(*command)
|
41
|
+
UI.command(shell_command) if print_command
|
42
|
+
|
43
|
+
result = ''
|
44
|
+
exit_status = nil
|
45
|
+
if Helper.sh_enabled?
|
46
|
+
# The argument list is passed directly to Open3.popen2e, which
|
47
|
+
# handles the variadic argument list in the same way as Kernel#spawn.
|
48
|
+
# (http://ruby-doc.org/core-2.4.2/Kernel.html#method-i-spawn) or
|
49
|
+
# Process.spawn (http://ruby-doc.org/core-2.4.2/Process.html#method-c-spawn).
|
50
|
+
#
|
51
|
+
# sh "ls -la /Applications/Xcode\ 7.3.1.app"
|
52
|
+
# sh "ls", "-la", "/Applications/Xcode 7.3.1.app"
|
53
|
+
# sh({ "FOO" => "Hello" }, "echo $FOO")
|
54
|
+
Open3.popen2e(*command) do |stdin, io, thread|
|
55
|
+
io.sync = true
|
56
|
+
io.each do |line|
|
57
|
+
UI.command_output(line.strip) if print_command_output
|
58
|
+
result << line
|
59
|
+
end
|
60
|
+
exit_status = thread.value
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checking Process::Status#exitstatus instead of #success? makes for more
|
64
|
+
# testable code. (Tests mock exitstatus only.) This is also consistent
|
65
|
+
# with previous implementations of sh and... probably portable to all
|
66
|
+
# relevant platforms.
|
67
|
+
if exit_status.exitstatus != 0
|
68
|
+
message = if print_command
|
69
|
+
"Exit status of command '#{shell_command}' was #{exit_status.exitstatus} instead of 0."
|
70
|
+
else
|
71
|
+
"Shell command exited with exit status #{exit_status.exitstatus} instead of 0."
|
72
|
+
end
|
73
|
+
message += "\n#{result}" if print_command_output
|
74
|
+
|
75
|
+
if error_callback || block_given?
|
76
|
+
UI.error(message)
|
77
|
+
# block notified below, on success or failure
|
78
|
+
error_callback && error_callback.call(result)
|
79
|
+
else
|
80
|
+
UI.shell_error!(message)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
else
|
84
|
+
result << shell_command # only for the tests
|
85
|
+
end
|
86
|
+
|
87
|
+
if block_given?
|
88
|
+
# Avoid yielding nil in tests. $? will be meaningless, but calls to
|
89
|
+
# it will not crash. There is no Process::Status.new. The alternative
|
90
|
+
# is to move this inside the sh_enabled? check and not yield in tests.
|
91
|
+
return yield(exit_status || $?, result, shell_command)
|
92
|
+
end
|
93
|
+
result
|
94
|
+
rescue => ex
|
95
|
+
raise ex
|
96
|
+
ensure
|
97
|
+
Encoding.default_external = previous_encoding.first
|
98
|
+
Encoding.default_internal = previous_encoding.last
|
99
|
+
end
|
100
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
101
|
+
|
102
|
+
# Used to produce a shell command string from a list of arguments that may
|
103
|
+
# be passed to methods such as Kernel#system, Kernel#spawn and Open3.popen2e
|
104
|
+
# in order to print the command to the terminal. The same *args are passed
|
105
|
+
# directly to a system call (Open3.popen2e). This interpretation is not
|
106
|
+
# used when executing a command.
|
107
|
+
#
|
108
|
+
# @param args Any number of arguments used to construct a command
|
109
|
+
# @raise [ArgumentError] If no arguments passed
|
110
|
+
# @return [String] A shell command representing the arguments passed in
|
111
|
+
def self.shell_command_from_args(*args)
|
112
|
+
raise ArgumentError, "sh requires at least one argument" unless args.count > 0
|
113
|
+
|
114
|
+
command = ""
|
115
|
+
|
116
|
+
# Optional initial environment Hash
|
117
|
+
if args.first.kind_of?(Hash)
|
118
|
+
command = args.shift.map { |k, v| "#{k}=#{v.shellescape}" }.join(" ") + " "
|
119
|
+
end
|
120
|
+
|
121
|
+
# Support [ "/usr/local/bin/foo", "foo" ], "-x", ...
|
122
|
+
if args.first.kind_of?(Array)
|
123
|
+
command += args.shift.first.shellescape + " " + args.shelljoin
|
124
|
+
command.chomp!(" ")
|
125
|
+
elsif args.count == 1 && args.first.kind_of?(String)
|
126
|
+
command += args.first
|
127
|
+
else
|
128
|
+
command += args.shelljoin
|
129
|
+
end
|
130
|
+
|
131
|
+
command
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Pantograph
|
2
|
+
class JUnitGenerator
|
3
|
+
def self.generate(results)
|
4
|
+
# JUnit file documentation: http://llg.cubic.org/docs/junit/
|
5
|
+
# And http://nelsonwells.net/2012/09/how-jenkins-ci-parses-and-displays-junit-output/
|
6
|
+
# And http://windyroad.com.au/dl/Open%20Source/JUnit.xsd
|
7
|
+
|
8
|
+
containing_folder = ENV['FL_REPORT_PATH'] || PantographCore::PantographFolder.path || Dir.pwd
|
9
|
+
path = File.join(containing_folder, 'report.xml')
|
10
|
+
|
11
|
+
@steps = results
|
12
|
+
xml_path = File.join(Pantograph::ROOT, "lib/assets/report_template.xml.erb")
|
13
|
+
xml = ERB.new(File.read(xml_path)).result(binding) # https://web.archive.org/web/20160430190141/www.rrn.dk/rubys-erb-templating-system
|
14
|
+
|
15
|
+
xml = xml.gsub('system_', 'system-').delete("\e") # Jenkins can not parse 'ESC' symbol
|
16
|
+
|
17
|
+
begin
|
18
|
+
File.write(path, xml)
|
19
|
+
rescue => ex
|
20
|
+
UI.error(ex)
|
21
|
+
UI.error("Couldn't save report.xml at path '#{File.expand_path(path)}', make sure you have write access to the containing directory.")
|
22
|
+
end
|
23
|
+
|
24
|
+
return path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Pantograph
|
2
|
+
# Represents a lane
|
3
|
+
class Lane
|
4
|
+
attr_accessor :platform
|
5
|
+
|
6
|
+
attr_accessor :name
|
7
|
+
|
8
|
+
# @return [Array] An array containing the description of this lane
|
9
|
+
# Each item of the array is one line
|
10
|
+
attr_accessor :description
|
11
|
+
|
12
|
+
attr_accessor :block
|
13
|
+
|
14
|
+
# @return [Boolean] Is that a private lane that can't be called from the CLI?
|
15
|
+
attr_accessor :is_private
|
16
|
+
|
17
|
+
def initialize(platform: nil, name: nil, description: nil, block: nil, is_private: false)
|
18
|
+
UI.user_error!("description must be an array") unless description.kind_of?(Array)
|
19
|
+
UI.user_error!("lane name must not contain any spaces") if name.to_s.include?(" ")
|
20
|
+
UI.user_error!("lane name must start with :") unless name.kind_of?(Symbol)
|
21
|
+
|
22
|
+
self.class.verify_lane_name(name)
|
23
|
+
|
24
|
+
self.platform = platform
|
25
|
+
self.name = name
|
26
|
+
self.description = description
|
27
|
+
self.block = block
|
28
|
+
self.is_private = is_private
|
29
|
+
end
|
30
|
+
|
31
|
+
# Execute this lane
|
32
|
+
def call(parameters)
|
33
|
+
block.call(parameters || {})
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String] The lane + name of the lane. If there is no platform, it will only be the lane name
|
37
|
+
def pretty_name
|
38
|
+
[platform, name].reject(&:nil?).join(' ')
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
# Makes sure the lane name is valid
|
43
|
+
def verify_lane_name(name)
|
44
|
+
if self.black_list.include?(name.to_s)
|
45
|
+
UI.error("Lane name '#{name}' is invalid! Invalid names are #{self.black_list.join(', ')}.")
|
46
|
+
UI.user_error!("Lane name '#{name}' is invalid")
|
47
|
+
end
|
48
|
+
|
49
|
+
if self.gray_list.include?(name.to_sym)
|
50
|
+
UI.error("------------------------------------------------")
|
51
|
+
UI.error("Lane name '#{name}' should not be used because it is the name of a pantograph tool")
|
52
|
+
UI.error("It is recommended to not use '#{name}' as the name of your lane")
|
53
|
+
UI.error("------------------------------------------------")
|
54
|
+
# We still allow it, because we're nice
|
55
|
+
# Otherwise we might break existing setups
|
56
|
+
return
|
57
|
+
end
|
58
|
+
|
59
|
+
self.ensure_name_not_conflicts(name.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
def black_list
|
63
|
+
%w(
|
64
|
+
run
|
65
|
+
init
|
66
|
+
new_action
|
67
|
+
lanes
|
68
|
+
list
|
69
|
+
docs
|
70
|
+
action
|
71
|
+
actions
|
72
|
+
enable_auto_complete
|
73
|
+
new_plugin
|
74
|
+
add_plugin
|
75
|
+
install_plugins
|
76
|
+
update_plugins
|
77
|
+
search_plugins
|
78
|
+
help
|
79
|
+
env
|
80
|
+
update_pantograph
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def gray_list
|
85
|
+
Pantograph::TOOLS
|
86
|
+
end
|
87
|
+
|
88
|
+
def ensure_name_not_conflicts(name)
|
89
|
+
# First, check if there is a predefined method in the actions folder
|
90
|
+
return unless Actions.action_class_ref(name)
|
91
|
+
UI.error("------------------------------------------------")
|
92
|
+
UI.error("Name of the lane '#{name}' is already taken by the action named '#{name}'")
|
93
|
+
UI.error("------------------------------------------------")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Pantograph
|
2
|
+
class LaneList
|
3
|
+
# Print out the result of `generate`
|
4
|
+
|
5
|
+
def self.output(path)
|
6
|
+
puts(generate(path))
|
7
|
+
|
8
|
+
puts("Execute using `pantograph [lane_name]`".yellow)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.generate(path)
|
12
|
+
ff = Pantograph::PantFile.new(path)
|
13
|
+
lanes = ff.runner.lanes
|
14
|
+
|
15
|
+
output = ""
|
16
|
+
|
17
|
+
all_keys = lanes.keys.reject(&:nil?)
|
18
|
+
all_keys.unshift(nil) # because we want root elements on top. always! They have key nil
|
19
|
+
|
20
|
+
all_keys.each do |platform|
|
21
|
+
next if (lanes[platform] || []).count == 0
|
22
|
+
|
23
|
+
plat_text = platform
|
24
|
+
plat_text = "general" if platform.to_s.empty?
|
25
|
+
output += "\n--------- #{plat_text}---------\n".yellow
|
26
|
+
|
27
|
+
value = lanes[platform]
|
28
|
+
next unless value
|
29
|
+
|
30
|
+
value.each do |lane_name, lane|
|
31
|
+
next if lane.is_private
|
32
|
+
|
33
|
+
output += "----- pantograph #{lane.pretty_name}".green
|
34
|
+
if lane.description.count > 0
|
35
|
+
output += "\n" + lane.description.join("\n") + "\n\n"
|
36
|
+
else
|
37
|
+
output += "\n\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
output
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.output_json(path)
|
46
|
+
puts(JSON.pretty_generate(self.generate_json(path)))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a hash
|
50
|
+
def self.generate_json(path)
|
51
|
+
output = {}
|
52
|
+
return output if path.nil?
|
53
|
+
ff = Pantograph::PantFile.new(path)
|
54
|
+
|
55
|
+
all_keys = ff.runner.lanes.keys
|
56
|
+
|
57
|
+
all_keys.each do |platform|
|
58
|
+
next if (ff.runner.lanes[platform] || []).count == 0
|
59
|
+
|
60
|
+
output[platform] ||= {}
|
61
|
+
|
62
|
+
value = ff.runner.lanes[platform]
|
63
|
+
next unless value
|
64
|
+
|
65
|
+
value.each do |lane_name, lane|
|
66
|
+
next if lane.is_private
|
67
|
+
|
68
|
+
output[platform][lane_name] = {
|
69
|
+
description: lane.description.join("\n")
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
return output
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|