hybrid_platforms_conductor 33.2.2 → 33.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -0
- data/README.md +29 -2
- data/docs/config_dsl.md +45 -0
- data/docs/plugins.md +1 -0
- data/docs/plugins/secrets_reader/keepass.md +62 -0
- data/lib/hybrid_platforms_conductor/bitbucket.rb +134 -90
- data/lib/hybrid_platforms_conductor/cmd_runner.rb +4 -4
- data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +12 -44
- data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +9 -31
- data/lib/hybrid_platforms_conductor/config.rb +0 -35
- data/lib/hybrid_platforms_conductor/confluence.rb +93 -88
- data/lib/hybrid_platforms_conductor/connector.rb +1 -1
- data/lib/hybrid_platforms_conductor/core_extensions/bundler/without_bundled_env.rb +18 -1
- data/lib/hybrid_platforms_conductor/credentials.rb +122 -97
- data/lib/hybrid_platforms_conductor/deployer.rb +37 -30
- data/lib/hybrid_platforms_conductor/github.rb +39 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/bash.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +27 -17
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +4 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +29 -20
- data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +1 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +5 -3
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox/reserve_proxmox_container +1 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +174 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +7 -3
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +8 -4
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +3 -1
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +24 -1
- data/lib/hybrid_platforms_conductor/plugins.rb +1 -0
- data/lib/hybrid_platforms_conductor/safe_merge.rb +37 -0
- data/lib/hybrid_platforms_conductor/thycotic.rb +80 -75
- data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +5 -3
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test.rb +10 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/bash_spec.rb +15 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +32 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +9 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +8 -6
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +38 -0
- data/spec/hybrid_platforms_conductor_test/api/cmd_runner_spec.rb +21 -1
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +48 -72
- data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +251 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +36 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/keepass_spec.rb +680 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +2 -2
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +2 -2
- data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +1 -1
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +49 -69
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +29 -39
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +21 -15
- data/spec/hybrid_platforms_conductor_test/test_connector.rb +2 -2
- metadata +188 -139
@@ -59,7 +59,7 @@ module HybridPlatformsConductor
|
|
59
59
|
# Raise an exception if the exit status is not the expected one.
|
60
60
|
#
|
61
61
|
# Parameters::
|
62
|
-
# * *cmd* (String): Command to be run
|
62
|
+
# * *cmd* (String or SecretString): Command to be run
|
63
63
|
# * *log_to_file* (String or nil): Log file capturing stdout or stderr (or nil for none). [default: nil]
|
64
64
|
# * *log_to_stdout* (Boolean): Do we send the output to stdout? [default: true]
|
65
65
|
# * *log_stdout_to_io* (IO or nil): IO to send command's stdout to, or nil for none. [default: nil]
|
@@ -108,7 +108,7 @@ module HybridPlatformsConductor
|
|
108
108
|
bash_file = nil
|
109
109
|
if force_bash
|
110
110
|
bash_file = Tempfile.new('hpc_bash')
|
111
|
-
bash_file.write(cmd)
|
111
|
+
bash_file.write(cmd.to_unprotected)
|
112
112
|
bash_file.chmod 0o700
|
113
113
|
bash_file.close
|
114
114
|
cmd = "/bin/bash -c #{bash_file.path}"
|
@@ -136,7 +136,7 @@ module HybridPlatformsConductor
|
|
136
136
|
pty: true,
|
137
137
|
timeout: timeout,
|
138
138
|
uuid: false
|
139
|
-
).run!(cmd) do |stdout, stderr|
|
139
|
+
).run!(cmd.to_unprotected) do |stdout, stderr|
|
140
140
|
stdout_queue << stdout if stdout
|
141
141
|
stderr_queue << stderr if stderr
|
142
142
|
end
|
@@ -162,7 +162,7 @@ module HybridPlatformsConductor
|
|
162
162
|
log_debug "Finished in #{elapsed} seconds with exit status #{exit_status} (#{(expected_code.include?(exit_status) ? 'success'.light_green : 'failure'.light_red).bold})"
|
163
163
|
end
|
164
164
|
unless expected_code.include?(exit_status)
|
165
|
-
error_title = "Command '#{cmd.split("\n").first}' returned error code #{exit_status} (expected #{expected_code.join(', ')})."
|
165
|
+
error_title = "Command '#{cmd.to_s.split("\n").first}' returned error code #{exit_status} (expected #{expected_code.join(', ')})."
|
166
166
|
if no_exception
|
167
167
|
# We consider the caller is responsible for logging what he wants about the details of the error (stdout and stderr)
|
168
168
|
log_error error_title
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'hybrid_platforms_conductor/bitbucket'
|
2
|
-
|
3
1
|
module HybridPlatformsConductor
|
4
2
|
|
5
3
|
module CommonConfigDsl
|
@@ -7,12 +5,21 @@ module HybridPlatformsConductor
|
|
7
5
|
# Add common Bitbucket config DSL to declare known Bitbucket repositories
|
8
6
|
module Bitbucket
|
9
7
|
|
8
|
+
# List of known Bitbucket repos
|
9
|
+
# Array< Hash<Symbol, Object> >
|
10
|
+
# * *url* (String): URL to the Bitbucket server
|
11
|
+
# * *project* (String): Project name from the Bitbucket server, storing repositories
|
12
|
+
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all
|
13
|
+
# * *jenkins_ci_url* (String or nil): Corresponding Jenkins CI URL, or nil if none
|
14
|
+
# * *checks* (Hash<Symbol, Object>): Checks definition to be perform on those repositories (see the #for_each_bitbucket_repo to know the structure)
|
15
|
+
attr_reader :known_bitbucket_repos
|
16
|
+
|
10
17
|
# Initialize the DSL
|
11
18
|
def init_bitbucket
|
12
19
|
# List of Bitbucket repositories definitions
|
13
20
|
# Array< Hash<Symbol, Object> >
|
14
|
-
# Each definition is just mapping the signature of #
|
15
|
-
@
|
21
|
+
# Each definition is just mapping the signature of #known_bitbucket_repos
|
22
|
+
@known_bitbucket_repos = []
|
16
23
|
end
|
17
24
|
|
18
25
|
# Register new Bitbucket repositories
|
@@ -24,7 +31,7 @@ module HybridPlatformsConductor
|
|
24
31
|
# * *jenkins_ci_url* (String or nil): Corresponding Jenkins CI URL, or nil if none [default: nil]
|
25
32
|
# * *checks* (Hash<Symbol, Object>): Checks definition to be perform on those repositories (see the #for_each_bitbucket_repo to know the structure) [default: {}]
|
26
33
|
def bitbucket_repos(url:, project:, repos: :all, jenkins_ci_url: nil, checks: {})
|
27
|
-
@
|
34
|
+
@known_bitbucket_repos << {
|
28
35
|
url: url,
|
29
36
|
project: project,
|
30
37
|
repos: repos,
|
@@ -33,45 +40,6 @@ module HybridPlatformsConductor
|
|
33
40
|
}
|
34
41
|
end
|
35
42
|
|
36
|
-
# Iterate over each Bitbucket repository
|
37
|
-
#
|
38
|
-
# Parameters::
|
39
|
-
# * Proc: Code called for each Bitbucket repository:
|
40
|
-
# * Parameters::
|
41
|
-
# * *bitbucket* (Bitbucket): The Bitbucket instance used to query the API for this repository
|
42
|
-
# * *repo_info* (Hash<Symbol, Object>): The repository info:
|
43
|
-
# * *name* (String): Repository name.
|
44
|
-
# * *project* (String): Project name.
|
45
|
-
# * *url* (String): Project Git URL.
|
46
|
-
# * *jenkins_ci_url* (String or nil): Corresponding Jenkins CI URL, or nil if none.
|
47
|
-
# * *checks* (Hash<Symbol, Object>): Checks to be performed on this repository:
|
48
|
-
# * *branch_permissions* (Array< Hash<Symbol, Object> >): List of branch permissions to check [optional]
|
49
|
-
# * *type* (String): Type of branch permissions to check. Examples of values are 'fast-forward-only', 'no-deletes', 'pull-request-only'.
|
50
|
-
# * *branch* (String): Branch on which those permissions apply.
|
51
|
-
# * *exempted_users* (Array<String>): List of exempted users for this permission [default: []]
|
52
|
-
# * *exempted_groups* (Array<String>): List of exempted groups for this permission [default: []]
|
53
|
-
# * *exempted_keys* (Array<String>): List of exempted access keys for this permission [default: []]
|
54
|
-
# * *pr_settings* (Hash<Symbol, Object>): PR specific settings to check [optional]
|
55
|
-
# * *required_approvers* (Integer): Number of required approvers [optional]
|
56
|
-
# * *required_builds* (Integer): Number of required successful builds [optional]
|
57
|
-
# * *default_merge_strategy* (String): Name of the default merge strategy. Example: 'rebase-no-ff' [optional]
|
58
|
-
# * *mandatory_default_reviewers* (Array<String>): List of mandatory reviewers to check [default: []]
|
59
|
-
def for_each_bitbucket_repo
|
60
|
-
@bitbucket_repos.each do |bitbucket_repo_info|
|
61
|
-
HybridPlatformsConductor::Bitbucket.with_bitbucket(bitbucket_repo_info[:url], @logger, @logger_stderr) do |bitbucket|
|
62
|
-
(bitbucket_repo_info[:repos] == :all ? bitbucket.repos(bitbucket_repo_info[:project])['values'].map { |repo_info| repo_info['slug'] } : bitbucket_repo_info[:repos]).each do |name|
|
63
|
-
yield bitbucket, {
|
64
|
-
name: name,
|
65
|
-
project: bitbucket_repo_info[:project],
|
66
|
-
url: "#{bitbucket_repo_info[:url]}/scm/#{bitbucket_repo_info[:project].downcase}/#{name}.git",
|
67
|
-
jenkins_ci_url: bitbucket_repo_info[:jenkins_ci_url].nil? ? nil : "#{bitbucket_repo_info[:jenkins_ci_url]}/job/#{name}",
|
68
|
-
checks: bitbucket_repo_info[:checks]
|
69
|
-
}
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
43
|
end
|
76
44
|
|
77
45
|
end
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'octokit'
|
2
|
-
require 'hybrid_platforms_conductor/credentials'
|
3
|
-
|
4
1
|
module HybridPlatformsConductor
|
5
2
|
|
6
3
|
module CommonConfigDsl
|
@@ -8,12 +5,19 @@ module HybridPlatformsConductor
|
|
8
5
|
# Add common Github config DSL to declare known Github repositories
|
9
6
|
module Github
|
10
7
|
|
8
|
+
# List of Github repositories
|
9
|
+
# Array< Hash<Symbol, Object> >
|
10
|
+
# * *user* (String): User or organization name, storing repositories
|
11
|
+
# * *url* (String): URL to the Github API
|
12
|
+
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all
|
13
|
+
attr_reader :known_github_repos
|
14
|
+
|
11
15
|
# Initialize the DSL
|
12
16
|
def init_github
|
13
17
|
# List of Github repositories definitions
|
14
18
|
# Array< Hash<Symbol, Object> >
|
15
19
|
# Each definition is just mapping the signature of #github_repos
|
16
|
-
@
|
20
|
+
@known_github_repos = []
|
17
21
|
end
|
18
22
|
|
19
23
|
# Register new Github repositories
|
@@ -23,39 +27,13 @@ module HybridPlatformsConductor
|
|
23
27
|
# * *url* (String): URL to the Github API [default: 'https://api.github.com']
|
24
28
|
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all [default: :all]
|
25
29
|
def github_repos(user:, url: 'https://api.github.com', repos: :all)
|
26
|
-
@
|
30
|
+
@known_github_repos << {
|
27
31
|
url: url,
|
28
32
|
user: user,
|
29
33
|
repos: repos
|
30
34
|
}
|
31
35
|
end
|
32
36
|
|
33
|
-
# Iterate over each Github repository
|
34
|
-
#
|
35
|
-
# Parameters::
|
36
|
-
# * Proc: Code called for each Github repository:
|
37
|
-
# * Parameters::
|
38
|
-
# * *github* (Octokit::Client): The client instance accessing the Github API
|
39
|
-
# * *repo_info* (Hash<Symbol, Object>): The repository info:
|
40
|
-
# * *name* (String): Repository name.
|
41
|
-
# * *slug* (String): Repository slug.
|
42
|
-
def for_each_github_repo
|
43
|
-
@github_repos.each do |repo_info|
|
44
|
-
Octokit.configure do |c|
|
45
|
-
c.api_endpoint = repo_info[:url]
|
46
|
-
end
|
47
|
-
Credentials.with_credentials_for(:github, @logger, @logger_stderr, url: repo_info[:url]) do |_github_user, github_token|
|
48
|
-
client = Octokit::Client.new(access_token: github_token)
|
49
|
-
(repo_info[:repos] == :all ? client.repositories(repo_info[:user]).map { |repo| repo[:name] } : repo_info[:repos]).each do |name|
|
50
|
-
yield client, {
|
51
|
-
name: name,
|
52
|
-
slug: "#{repo_info[:user]}/#{name}"
|
53
|
-
}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
37
|
end
|
60
38
|
|
61
39
|
end
|
@@ -47,12 +47,6 @@ module HybridPlatformsConductor
|
|
47
47
|
# Array<Hash,Symbol,Object>
|
48
48
|
attr_reader :expected_failures
|
49
49
|
|
50
|
-
# List of retriable errors. Each info has the following properties:
|
51
|
-
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
52
|
-
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
53
|
-
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
54
|
-
attr_reader :retriable_errors
|
55
|
-
|
56
50
|
# List of deployment schedules. Each info has the following properties:
|
57
51
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
58
52
|
# * *schedule* (IceCube::Schedule): The deployment schedule
|
@@ -81,11 +75,6 @@ module HybridPlatformsConductor
|
|
81
75
|
# * *reason* (String): Reason for this expected failure
|
82
76
|
# Array<Hash,Symbol,Object>
|
83
77
|
@expected_failures = []
|
84
|
-
# List of retriable errors. Each info has the following properties:
|
85
|
-
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by those errors
|
86
|
-
# * *errors_on_stdout* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stdout
|
87
|
-
# * *errors_on_stderr* (Array<String or Regexp>): List of errors match (as exact string match or using a regexp) to check against stderr
|
88
|
-
@retriable_errors = []
|
89
78
|
# List of deployment schedules. Each info has the following properties:
|
90
79
|
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule
|
91
80
|
# * *schedule* (IceCube::Schedule): The deployment schedule
|
@@ -162,30 +151,6 @@ module HybridPlatformsConductor
|
|
162
151
|
end
|
163
152
|
expose :expect_tests_to_fail
|
164
153
|
|
165
|
-
# Mark some errors on stdout to be retriable during a deploy
|
166
|
-
#
|
167
|
-
# Parameters::
|
168
|
-
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
169
|
-
def retry_deploy_for_errors_on_stdout(errors)
|
170
|
-
@retriable_errors << {
|
171
|
-
errors_on_stdout: errors.is_a?(Array) ? errors : [errors],
|
172
|
-
nodes_selectors_stack: current_nodes_selectors_stack
|
173
|
-
}
|
174
|
-
end
|
175
|
-
expose :retry_deploy_for_errors_on_stdout
|
176
|
-
|
177
|
-
# Mark some errors on stderr to be retriable during a deploy
|
178
|
-
#
|
179
|
-
# Parameters::
|
180
|
-
# * *errors* (String, Regexp or Array<String or Regexp>): Single (or list of) errors matching pattern (either as exact string match or using a regexp).
|
181
|
-
def retry_deploy_for_errors_on_stderr(errors)
|
182
|
-
@retriable_errors << {
|
183
|
-
errors_on_stderr: errors.is_a?(Array) ? errors : [errors],
|
184
|
-
nodes_selectors_stack: current_nodes_selectors_stack
|
185
|
-
}
|
186
|
-
end
|
187
|
-
expose :retry_deploy_for_errors_on_stderr
|
188
|
-
|
189
154
|
# Set a deployment schedule
|
190
155
|
#
|
191
156
|
# Parameters::
|
@@ -7,111 +7,116 @@ require 'hybrid_platforms_conductor/credentials'
|
|
7
7
|
|
8
8
|
module HybridPlatformsConductor
|
9
9
|
|
10
|
-
#
|
11
|
-
|
10
|
+
# Mixin used to access Confluence API
|
11
|
+
module Confluence
|
12
12
|
|
13
|
-
include
|
13
|
+
include Credentials
|
14
14
|
|
15
15
|
# Provide a Confluence connector, and make sure the password is being cleaned when exiting.
|
16
16
|
#
|
17
17
|
# Parameters::
|
18
18
|
# * *confluence_url* (String): The Confluence URL
|
19
|
-
# * *logger* (Logger): Logger to be used
|
20
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr
|
21
19
|
# * Proc: Code called with the Confluence instance.
|
22
|
-
# * *confluence* (
|
23
|
-
def
|
24
|
-
|
25
|
-
yield
|
20
|
+
# * *confluence* (ConfluenceApi): The Confluence instance to use.
|
21
|
+
def with_confluence(confluence_url)
|
22
|
+
with_credentials_for(:confluence, resource: confluence_url) do |confluence_user, confluence_password|
|
23
|
+
yield ConfluenceApi.new(confluence_url, confluence_user, confluence_password, logger: @logger, logger_stderr: @logger_stderr)
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
|
-
#
|
30
|
-
|
31
|
-
# Parameters::
|
32
|
-
# * *confluence_url* (String): The Confluence URL
|
33
|
-
# * *confluence_user_name* (String): Confluence user name to be used when querying the API
|
34
|
-
# * *confluence_password* (String): Confluence password to be used when querying the API
|
35
|
-
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
36
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
37
|
-
def initialize(confluence_url, confluence_user_name, confluence_password, logger: Logger.new($stdout), logger_stderr: Logger.new($stderr))
|
38
|
-
init_loggers(logger, logger_stderr)
|
39
|
-
@confluence_url = confluence_url
|
40
|
-
@confluence_user_name = confluence_user_name
|
41
|
-
@confluence_password = confluence_password
|
42
|
-
end
|
27
|
+
# Provide an API access on Confluence
|
28
|
+
class ConfluenceApi
|
43
29
|
|
44
|
-
|
45
|
-
#
|
46
|
-
# Parameters::
|
47
|
-
# * *page_id* (String): Confluence page ID
|
48
|
-
# Result::
|
49
|
-
# * Nokogiri::HTML: Storage format content, as a Nokogiri object
|
50
|
-
def page_storage_format(page_id)
|
51
|
-
Nokogiri::HTML(call_api("plugins/viewstorage/viewpagestorage.action?pageId=#{page_id}").body)
|
52
|
-
end
|
30
|
+
include LoggerHelpers
|
53
31
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
32
|
+
# Constructor
|
33
|
+
#
|
34
|
+
# Parameters::
|
35
|
+
# * *confluence_url* (String): The Confluence URL
|
36
|
+
# * *confluence_user_name* (String): Confluence user name to be used when querying the API
|
37
|
+
# * *confluence_password* (SecretString): Confluence password to be used when querying the API
|
38
|
+
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
39
|
+
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
40
|
+
def initialize(confluence_url, confluence_user_name, confluence_password, logger: Logger.new($stdout), logger_stderr: Logger.new($stderr))
|
41
|
+
init_loggers(logger, logger_stderr)
|
42
|
+
@confluence_url = confluence_url
|
43
|
+
@confluence_user_name = confluence_user_name
|
44
|
+
@confluence_password = confluence_password
|
45
|
+
end
|
63
46
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
version = info['version']['number'] + 1 if version.nil?
|
73
|
-
log_debug "Update Confluence page #{page_id}..."
|
74
|
-
call_api("rest/api/content/#{page_id}", :put) do |request|
|
75
|
-
request['Content-Type'] = 'application/json'
|
76
|
-
request.body = {
|
77
|
-
type: 'page',
|
78
|
-
title: info['title'],
|
79
|
-
body: {
|
80
|
-
storage: {
|
81
|
-
value: content,
|
82
|
-
representation: 'storage'
|
83
|
-
}
|
84
|
-
},
|
85
|
-
version: { number: version }
|
86
|
-
}.to_json
|
47
|
+
# Return a Confluence storage format content from a page ID
|
48
|
+
#
|
49
|
+
# Parameters::
|
50
|
+
# * *page_id* (String): Confluence page ID
|
51
|
+
# Result::
|
52
|
+
# * Nokogiri::HTML: Storage format content, as a Nokogiri object
|
53
|
+
def page_storage_format(page_id)
|
54
|
+
Nokogiri::HTML(call_api("plugins/viewstorage/viewpagestorage.action?pageId=#{page_id}").body)
|
87
55
|
end
|
88
|
-
end
|
89
56
|
|
90
|
-
|
57
|
+
# Return some info of a given page ID
|
58
|
+
#
|
59
|
+
# Parameters::
|
60
|
+
# * *page_id* (String): Confluence page ID
|
61
|
+
# Result::
|
62
|
+
# * Hash: Page information, as returned by the Confluence API
|
63
|
+
def page_info(page_id)
|
64
|
+
JSON.parse(call_api("rest/api/content/#{page_id}").body)
|
65
|
+
end
|
91
66
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
67
|
+
# Update a Confluence page to a new content.
|
68
|
+
#
|
69
|
+
# Parameters::
|
70
|
+
# * *page_id* (String): Confluence page ID
|
71
|
+
# * *content* (String): New content
|
72
|
+
# * *version* (String or nil): New version, or nil to automatically increase last existing version [default: nil]
|
73
|
+
def update_page(page_id, content, version: nil)
|
74
|
+
info = page_info(page_id)
|
75
|
+
version = info['version']['number'] + 1 if version.nil?
|
76
|
+
log_debug "Update Confluence page #{page_id}..."
|
77
|
+
call_api("rest/api/content/#{page_id}", :put) do |request|
|
78
|
+
request['Content-Type'] = 'application/json'
|
79
|
+
request.body = {
|
80
|
+
type: 'page',
|
81
|
+
title: info['title'],
|
82
|
+
body: {
|
83
|
+
storage: {
|
84
|
+
value: content,
|
85
|
+
representation: 'storage'
|
86
|
+
}
|
87
|
+
},
|
88
|
+
version: { number: version }
|
89
|
+
}.to_json
|
90
|
+
end
|
113
91
|
end
|
114
|
-
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Call the Confluence API for a given URL and HTTP verb.
|
96
|
+
# Provide a simple way to tweak the request with an optional proc.
|
97
|
+
# Automatically handles authentication, base URL and error handling.
|
98
|
+
#
|
99
|
+
# Parameters::
|
100
|
+
# * *api_path* (String): The API path to query
|
101
|
+
# * *http_method* (Symbol): HTTP method to be used to create the request [default = :get]
|
102
|
+
# * Proc: Optional code called to alter the request
|
103
|
+
# * Parameters::
|
104
|
+
# * *request* (Net::HTTPRequest): The request
|
105
|
+
# Result::
|
106
|
+
# * Net::HTTPResponse: The corresponding response
|
107
|
+
def call_api(api_path, http_method = :get)
|
108
|
+
response = nil
|
109
|
+
page_url = URI.parse("#{@confluence_url}/#{api_path}")
|
110
|
+
Net::HTTP.start(page_url.host, page_url.port, use_ssl: true) do |http|
|
111
|
+
request = Net::HTTP.const_get(http_method.to_s.capitalize.to_sym).new(page_url.request_uri)
|
112
|
+
request.basic_auth @confluence_user_name, @confluence_password&.to_unprotected
|
113
|
+
yield request if block_given?
|
114
|
+
response = http.request(request)
|
115
|
+
raise "Confluence page API request on #{page_url} returned an error: #{response.code}\n#{response.body}\n===== Request body =====\n#{request.body}" unless response.is_a?(Net::HTTPSuccess)
|
116
|
+
end
|
117
|
+
response
|
118
|
+
end
|
119
|
+
|
115
120
|
end
|
116
121
|
|
117
122
|
end
|
@@ -67,7 +67,7 @@ module HybridPlatformsConductor
|
|
67
67
|
# Handle the redirection of standard output and standard error to file and stdout depending on the context of the run.
|
68
68
|
#
|
69
69
|
# Parameters::
|
70
|
-
# * *cmd* (String): The command to be run
|
70
|
+
# * *cmd* (String or SecretString): The command to be run
|
71
71
|
# * *force_bash* (Boolean): If true, then make sure command is invoked with bash instead of sh [default: false]
|
72
72
|
# Result::
|
73
73
|
# * Integer: Exit code
|