xapixctl 1.0.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/cd.yaml +17 -0
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -1
- data/Gemfile.lock +63 -41
- data/README.md +8 -0
- data/Rakefile +1 -1
- data/lib/xapixctl.rb +0 -3
- data/lib/xapixctl/base_cli.rb +75 -0
- data/lib/xapixctl/cli.rb +68 -136
- data/lib/xapixctl/phoenix_client.rb +58 -142
- data/lib/xapixctl/phoenix_client/connection.rb +50 -0
- data/lib/xapixctl/phoenix_client/organization_connection.rb +61 -0
- data/lib/xapixctl/phoenix_client/project_connection.rb +164 -0
- data/lib/xapixctl/phoenix_client/result_handler.rb +35 -0
- data/lib/xapixctl/preview_cli.rb +54 -0
- data/lib/xapixctl/sync_cli.rb +166 -0
- data/lib/xapixctl/util.rb +42 -0
- data/lib/xapixctl/version.rb +3 -1
- data/xapixctl.gemspec +16 -9
- metadata +93 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 175a3c54493e14738757b5eb95ef1da9724b961f460d1ac5dfb17ea6eb696507
|
4
|
+
data.tar.gz: 0a79951ab81a2b69d0087161191097cf24b01e2282887d03b12e8f32527d3707
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 040c017fb340670f8751a45c5b9c0c659cd814bb712cc74fb40e368f714fb1b80759d9c4387cbbb19999cfd512fc389a082168cde33f67cc1fd9fa0fb17b42f3
|
7
|
+
data.tar.gz: 1bdbbbb3da472ade7b520cfebc284ebebdeb871ee77c3bafa5fb22789bf4c0057d4dc7ff116ee3c0d611dbd692d99a96ac168ffa8824be006b22b124c7e98bf7
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: CD
|
2
|
+
on: push
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
runs-on: ubuntu-latest
|
6
|
+
strategy:
|
7
|
+
matrix:
|
8
|
+
ruby-version: [2.7, 2.6]
|
9
|
+
steps:
|
10
|
+
- uses: actions/checkout@v2
|
11
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
12
|
+
uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
ruby-version: ${{ matrix.ruby-version }}
|
15
|
+
bundler-cache: true
|
16
|
+
- name: Run tests
|
17
|
+
run: bundle exec rspec
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
2
|
+
NewCops: enable
|
3
|
+
TargetRubyVersion: 2.6
|
3
4
|
DisplayCopNames: true
|
4
5
|
Exclude:
|
5
6
|
- bin/*
|
@@ -25,3 +26,6 @@ Style/OptionHash:
|
|
25
26
|
Metrics/BlockLength:
|
26
27
|
Exclude:
|
27
28
|
- spec/**/*
|
29
|
+
|
30
|
+
Naming/RescuedExceptionsVariableName:
|
31
|
+
PreferredName: 'err'
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.3
|
data/Gemfile.lock
CHANGED
@@ -1,86 +1,108 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
xapixctl (1.
|
5
|
-
activesupport (
|
6
|
-
rest-client (
|
7
|
-
thor (
|
4
|
+
xapixctl (1.2.1)
|
5
|
+
activesupport (>= 5.2.3, < 6.0.0)
|
6
|
+
rest-client (>= 2.1.0, < 3.0.0)
|
7
|
+
thor (>= 1.0.0, < 1.2.0)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activesupport (5.2.4.
|
12
|
+
activesupport (5.2.4.5)
|
13
13
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
14
|
i18n (>= 0.7, < 2)
|
15
15
|
minitest (~> 5.1)
|
16
16
|
tzinfo (~> 1.1)
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
addressable (2.7.0)
|
18
|
+
public_suffix (>= 2.0.2, < 5.0)
|
19
|
+
ast (2.4.2)
|
20
|
+
concurrent-ruby (1.1.8)
|
21
|
+
crack (0.4.4)
|
22
|
+
diff-lcs (1.4.4)
|
20
23
|
domain_name (0.5.20190701)
|
21
24
|
unf (>= 0.0.5, < 1.0.0)
|
25
|
+
hashdiff (1.0.1)
|
22
26
|
http-accept (1.7.0)
|
23
27
|
http-cookie (1.0.3)
|
24
28
|
domain_name (~> 0.5)
|
25
|
-
i18n (1.8.
|
29
|
+
i18n (1.8.9)
|
26
30
|
concurrent-ruby (~> 1.0)
|
27
|
-
jaro_winkler (1.5.4)
|
28
31
|
mime-types (3.3.1)
|
29
32
|
mime-types-data (~> 3.2015)
|
30
|
-
mime-types-data (3.
|
31
|
-
minitest (5.14.
|
33
|
+
mime-types-data (3.2021.0225)
|
34
|
+
minitest (5.14.4)
|
32
35
|
netrc (0.11.0)
|
33
|
-
parallel (1.
|
34
|
-
parser (
|
35
|
-
ast (~> 2.4.
|
36
|
+
parallel (1.20.1)
|
37
|
+
parser (3.0.0.0)
|
38
|
+
ast (~> 2.4.1)
|
39
|
+
public_suffix (4.0.6)
|
36
40
|
rainbow (3.0.0)
|
37
|
-
rake (
|
41
|
+
rake (13.0.3)
|
42
|
+
regexp_parser (2.1.1)
|
38
43
|
relaxed-rubocop (2.5)
|
39
44
|
rest-client (2.1.0)
|
40
45
|
http-accept (>= 1.7.0, < 2.0)
|
41
46
|
http-cookie (>= 1.0.2, < 2.0)
|
42
47
|
mime-types (>= 1.16, < 4.0)
|
43
48
|
netrc (~> 0.8)
|
44
|
-
|
45
|
-
|
46
|
-
rspec-
|
47
|
-
rspec-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
rexml (3.2.4)
|
50
|
+
rspec (3.10.0)
|
51
|
+
rspec-core (~> 3.10.0)
|
52
|
+
rspec-expectations (~> 3.10.0)
|
53
|
+
rspec-mocks (~> 3.10.0)
|
54
|
+
rspec-core (3.10.1)
|
55
|
+
rspec-support (~> 3.10.0)
|
56
|
+
rspec-expectations (3.10.1)
|
51
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
52
|
-
rspec-support (~> 3.
|
53
|
-
rspec-mocks (3.
|
58
|
+
rspec-support (~> 3.10.0)
|
59
|
+
rspec-mocks (3.10.2)
|
54
60
|
diff-lcs (>= 1.2.0, < 2.0)
|
55
|
-
rspec-support (~> 3.
|
56
|
-
rspec-support (3.
|
57
|
-
rubocop (
|
58
|
-
jaro_winkler (~> 1.5.1)
|
61
|
+
rspec-support (~> 3.10.0)
|
62
|
+
rspec-support (3.10.2)
|
63
|
+
rubocop (1.11.0)
|
59
64
|
parallel (~> 1.10)
|
60
|
-
parser (>=
|
65
|
+
parser (>= 3.0.0.0)
|
61
66
|
rainbow (>= 2.2.2, < 4.0)
|
67
|
+
regexp_parser (>= 1.8, < 3.0)
|
68
|
+
rexml
|
69
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
62
70
|
ruby-progressbar (~> 1.7)
|
63
|
-
unicode-display_width (>= 1.4.0, <
|
64
|
-
|
65
|
-
|
71
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
72
|
+
rubocop-ast (1.4.1)
|
73
|
+
parser (>= 2.7.1.5)
|
74
|
+
rubocop-rake (0.5.1)
|
75
|
+
rubocop
|
76
|
+
rubocop-rspec (2.2.0)
|
77
|
+
rubocop (~> 1.0)
|
78
|
+
rubocop-ast (>= 1.1.0)
|
79
|
+
ruby-progressbar (1.11.0)
|
80
|
+
thor (1.1.0)
|
66
81
|
thread_safe (0.3.6)
|
67
|
-
tzinfo (1.2.
|
82
|
+
tzinfo (1.2.9)
|
68
83
|
thread_safe (~> 0.1)
|
69
84
|
unf (0.1.4)
|
70
85
|
unf_ext
|
71
|
-
unf_ext (0.0.7.
|
72
|
-
unicode-display_width (
|
86
|
+
unf_ext (0.0.7.7)
|
87
|
+
unicode-display_width (2.0.0)
|
88
|
+
webmock (3.11.0)
|
89
|
+
addressable (>= 2.3.6)
|
90
|
+
crack (>= 0.3.2)
|
91
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
73
92
|
|
74
93
|
PLATFORMS
|
75
94
|
ruby
|
76
95
|
|
77
96
|
DEPENDENCIES
|
78
|
-
bundler (~> 1.
|
79
|
-
rake (~>
|
97
|
+
bundler (~> 2.1.4)
|
98
|
+
rake (~> 13.0)
|
80
99
|
relaxed-rubocop (~> 2.5)
|
81
|
-
rspec (~> 3.0)
|
82
|
-
rubocop (~>
|
100
|
+
rspec (~> 3.10.0)
|
101
|
+
rubocop (~> 1.11.0)
|
102
|
+
rubocop-rake (~> 0.5.1)
|
103
|
+
rubocop-rspec (~> 2.2.0)
|
104
|
+
webmock (~> 3.11.0)
|
83
105
|
xapixctl!
|
84
106
|
|
85
107
|
BUNDLED WITH
|
86
|
-
1.
|
108
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# xapixctl
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/xapixctl.svg)](https://badge.fury.io/rb/xapixctl)
|
4
|
+
|
3
5
|
Xapix client library and command line tool
|
4
6
|
|
5
7
|
## Installation
|
@@ -8,6 +10,12 @@ Install it via:
|
|
8
10
|
|
9
11
|
$ gem install xapixctl
|
10
12
|
|
13
|
+
On Windows make sure you have ruby installed:
|
14
|
+
|
15
|
+
$ choco install ruby -y
|
16
|
+
$ refreshenv
|
17
|
+
$ gem install xapixctl
|
18
|
+
|
11
19
|
## Usage
|
12
20
|
|
13
21
|
To see more details on how to run xapixctl, use:
|
data/Rakefile
CHANGED
data/lib/xapixctl.rb
CHANGED
@@ -4,9 +4,6 @@ require 'active_support'
|
|
4
4
|
require 'active_support/core_ext/hash/keys'
|
5
5
|
require 'active_support/core_ext/object/blank'
|
6
6
|
require 'active_support/core_ext/string/inflections'
|
7
|
-
require 'rest_client'
|
8
|
-
require 'json'
|
9
|
-
require 'psych'
|
10
7
|
require 'xapixctl/version'
|
11
8
|
require 'xapixctl/phoenix_client'
|
12
9
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'xapixctl/util'
|
5
|
+
|
6
|
+
module Xapixctl
|
7
|
+
class BaseCli < Thor
|
8
|
+
def self.exit_on_failure?; true; end
|
9
|
+
|
10
|
+
def self.start(given_args = ARGV, config = {})
|
11
|
+
super
|
12
|
+
rescue StandardError => err
|
13
|
+
config[:debug] || ENV["THOR_DEBUG"] == "1" ? (raise err) : config[:shell].error(err.message)
|
14
|
+
exit(false) if exit_on_failure?
|
15
|
+
end
|
16
|
+
|
17
|
+
class_option :org, aliases: "-o", desc: "Organization; Fallback: environment variable XAPIX_ORG"
|
18
|
+
class_option :project, aliases: "-p", desc: "Project, can be ORG/PROJECT; Fallback: environment variable XAPIX_PROJECT"
|
19
|
+
class_option :debug, type: :boolean, desc: "Print details for debugging"
|
20
|
+
class_option :xapix_url, desc: "Fallback: environment variable XAPIX_URL. URL to Xapix. Default: https://cloud.xapix.io/"
|
21
|
+
class_option :xapix_token, desc: "Fallback: environment variable XAPIX_TOKEN. Your access token."
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def exit_with_api_error(err, result)
|
26
|
+
details = result['errors'].map { |k| k['detail'] }.unshift('').join("\n ") rescue err.to_s
|
27
|
+
warn "API error: #{details}"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def show_deployment_status(result)
|
32
|
+
return unless result && result['project_publication']
|
33
|
+
puts "deployment: #{result.dig('project_publication', 'deployment')}"
|
34
|
+
puts " data api: #{result.dig('project_publication', 'data_api')} (version: #{result.dig('project_publication', 'data_api_version').presence || 'n/a'})"
|
35
|
+
puts " user management: #{result.dig('project_publication', 'user_management')}"
|
36
|
+
if result.dig('project_publication', 'deployment') == 'success'
|
37
|
+
puts " base URL: #{result.dig('project_publication', 'base_url')}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def connection
|
42
|
+
@connection ||= begin
|
43
|
+
url = options[:xapix_url] || ENV['XAPIX_URL'] || 'https://cloud.xapix.io/'
|
44
|
+
token = options[:xapix_token] || ENV['XAPIX_TOKEN']
|
45
|
+
raise Thor::RequiredArgumentMissingError, "No XAPIX_TOKEN given. Either use --xapix_token [TOKEN] or set environment variable XAPIX_TOKEN (recommended)" if !token
|
46
|
+
PhoenixClient.connection(
|
47
|
+
url, token,
|
48
|
+
default_error_handler: ->(err, result) { exit_with_api_error(err, result) },
|
49
|
+
logging: options[:debug] ? 'stdout' : nil
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def org_or_prj_connection
|
55
|
+
options[:project] ? prj_connection : org_connection
|
56
|
+
end
|
57
|
+
|
58
|
+
def org_connection
|
59
|
+
org = options[:org] || ENV['XAPIX_ORG']
|
60
|
+
raise Thor::RequiredArgumentMissingError, "No organization given. Either use --org [ORG] or set environment variable XAPIX_ORG" if !org
|
61
|
+
@org_connection ||= connection.organization(org)
|
62
|
+
end
|
63
|
+
|
64
|
+
def prj_connection
|
65
|
+
project = options[:project] || ENV['XAPIX_PROJECT']
|
66
|
+
org = options[:org] || ENV['XAPIX_ORG']
|
67
|
+
raise Thor::RequiredArgumentMissingError, "No project given. Either use --project [ORG/PROJECT] or set environment variable XAPIX_PROJECT" if !project
|
68
|
+
if project.include?('/')
|
69
|
+
org, project = project.split('/', 2)
|
70
|
+
end
|
71
|
+
raise Thor::RequiredArgumentMissingError, "No organization given. Either use --org [ORG] or set environment variable XAPIX_ORG" if !org
|
72
|
+
@prj_connection ||= connection.project(org: org, project: project)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/xapixctl/cli.rb
CHANGED
@@ -1,232 +1,164 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'xapixctl/base_cli'
|
4
|
+
require 'xapixctl/preview_cli'
|
5
|
+
require 'xapixctl/sync_cli'
|
4
6
|
|
5
7
|
module Xapixctl
|
6
|
-
class Cli <
|
7
|
-
|
8
|
+
class Cli < BaseCli
|
9
|
+
desc "preview SUBCOMMAND ...ARGS", "Request preview for resources"
|
10
|
+
subcommand "preview", PreviewCli
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
class_option :xapix_token, desc: "Fallback: environment variable XAPIX_TOKEN. Your access token."
|
12
|
+
desc "sync SUBCOMMAND ...ARGS", "Sync resources"
|
13
|
+
subcommand "sync", SyncCli
|
12
14
|
|
13
|
-
option :org, aliases: "-o", desc: "Organization", required: true
|
14
|
-
option :project, aliases: "-p", desc: "Project"
|
15
15
|
option :format, aliases: "-f", default: 'text', enum: ['text', 'yaml', 'json'], desc: "Output format"
|
16
16
|
desc "get TYPE [ID]", "retrieve either all resources of given TYPE or just the resource of given TYPE and ID"
|
17
17
|
long_desc <<-LONGDESC
|
18
|
-
`
|
18
|
+
`xapixctl get TYPE` will retrieve the list of all resources of given type.
|
19
19
|
|
20
20
|
If requested on an organization (i.e. no project given), the following types are available:
|
21
|
-
\
|
21
|
+
\x5Project
|
22
22
|
|
23
23
|
If requested on an a project (i.e. organization and project are given), the following types are available:
|
24
|
-
\x5
|
24
|
+
\x5#{PhoenixClient::SUPPORTED_RESOURCE_TYPES.sort.join(', ')}
|
25
25
|
|
26
26
|
Use the format to switch between the different output formats.
|
27
27
|
|
28
28
|
Examples:
|
29
|
-
\x5> $
|
30
|
-
\x5> $
|
31
|
-
\x5> $
|
32
|
-
\x5> $
|
29
|
+
\x5> $ xapixctl get -o xapix Project
|
30
|
+
\x5> $ xapixctl get -o xapix Project some-project
|
31
|
+
\x5> $ xapixctl get -o xapix -p some-project DataSource
|
32
|
+
\x5> $ xapixctl get -p xapix/some-project DataSource
|
33
|
+
\x5> $ xapixctl get -p xapix/some-project DataSource get-a-list
|
33
34
|
LONGDESC
|
34
35
|
def get(resource_type, resource_id = nil)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
else
|
41
|
-
connection.resource_ids(resource_type, org: options[:org], project: options[:project]) do |res|
|
42
|
-
res.on_success do |resource_ids|
|
43
|
-
resource_ids.each do |resource_id|
|
44
|
-
connection.resource(resource_type, resource_id, org: options[:org], project: options[:project], format: options[:format].to_sym) do |res|
|
45
|
-
res.on_success { |resource| puts resource }
|
46
|
-
res.on_error { |err, result| warn_api_error("could not get", err, result) }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
res.on_error { |err, result| warn_api_error("could not get", err, result) }
|
51
|
-
end
|
36
|
+
conn = org_or_prj_connection
|
37
|
+
resource_ids = resource_id ? [resource_id] : conn.resource_ids(resource_type)
|
38
|
+
resource_ids.each do |res_id|
|
39
|
+
puts conn.resource(resource_type, res_id, format: options[:format].to_sym)
|
52
40
|
end
|
53
41
|
end
|
54
42
|
|
55
|
-
option :org, aliases: "-o", desc: "Organization", required: true
|
56
|
-
option :project, aliases: "-p", desc: "Project", required: true
|
57
43
|
option :format, aliases: "-f", default: 'text', enum: ['text', 'yaml', 'json'], desc: "Output format"
|
58
44
|
desc "export", "retrieves all resources within a project"
|
59
45
|
long_desc <<-LONGDESC
|
60
|
-
`
|
46
|
+
`xapixctl export` will retrieve the list of all resources of given type.
|
61
47
|
|
62
48
|
Use the format to switch between the different output formats.
|
63
49
|
|
64
50
|
Examples:
|
65
|
-
\x5> $
|
66
|
-
\x5> $
|
51
|
+
\x5> $ xapixctl export -o xapix -p some-project
|
52
|
+
\x5> $ xapixctl export -p xapix/some-project
|
53
|
+
\x5> $ xapixctl export -p xapix/some-project -f yaml > some_project.yaml
|
67
54
|
LONGDESC
|
68
55
|
def export
|
69
|
-
|
70
|
-
|
71
|
-
res.on_error { |err, result| warn_api_error("could not get", err, result) }
|
72
|
-
end
|
73
|
-
(connection.resource_types_for_export - ['Project']).each { |type| get(type) }
|
56
|
+
get('Project', prj_connection.project)
|
57
|
+
prj_connection.resource_types_for_export.each { |type| get(type) }
|
74
58
|
end
|
75
59
|
|
76
|
-
option :
|
77
|
-
option :project, aliases: "-p", desc: "Project"
|
78
|
-
option :file, aliases: "-f", required: true
|
60
|
+
option :file, aliases: "-f", required: true, desc: 'file or directory from which to load resource descriptions'
|
79
61
|
desc "apply", "Create or update a resource from a file"
|
80
62
|
long_desc <<-LONGDESC
|
81
|
-
`
|
63
|
+
`xapixctl apply -f FILE` will apply the given resource description.
|
82
64
|
|
83
65
|
If applied on an organization (i.e. no project given), the project is taken from the resource description.
|
84
66
|
|
85
67
|
If applied on a project (i.e. organization and project are given), the given project is used.
|
86
68
|
|
87
69
|
The given file should be in YAML format and can contain multiple resource definitions, each as it's own YAML document.
|
70
|
+
You can also provide a directory, in which case all files with yml/yaml extension will get loaded.
|
88
71
|
You can also read from stdin by using '-'.
|
89
72
|
|
90
73
|
Examples:
|
91
|
-
\x5> $
|
92
|
-
\x5> $
|
74
|
+
\x5> $ xapixctl apply -o xapix -f get_a_list.yaml
|
75
|
+
\x5> $ xapixctl apply -o xapix -p some-project -f get_a_list.yaml
|
76
|
+
\x5> $ xapixctl apply -p xapix/some-project -f get_a_list.yaml
|
77
|
+
\x5> $ xapixctl apply -p xapix/some-project -f ./
|
93
78
|
|
94
79
|
To copy over all data sources from one project to another:
|
95
|
-
\x5> $
|
80
|
+
\x5> $ xapixctl get -o xapix-old -p some-project DataSource -f yaml | xapixctl apply -o xapix-new -f -
|
96
81
|
LONGDESC
|
97
82
|
def apply
|
98
|
-
resources_from_file(options[:file]) do |desc|
|
83
|
+
Util.resources_from_file(options[:file]) do |desc|
|
99
84
|
puts "applying #{desc['kind']} #{desc.dig('metadata', 'id')}"
|
100
|
-
|
101
|
-
res.on_success { puts 'OK' }
|
102
|
-
res.on_error { |err, result| warn_api_error("could not apply changes", err, result); break }
|
103
|
-
end
|
85
|
+
org_or_prj_connection.apply(desc)
|
104
86
|
end
|
105
87
|
end
|
106
88
|
|
107
|
-
option :
|
108
|
-
option :project, aliases: "-p", desc: "Project"
|
109
|
-
option :file, aliases: "-f"
|
89
|
+
option :file, aliases: "-f", desc: 'file or directory from which to load resource descriptions'
|
110
90
|
desc "delete [TYPE ID] [-f FILE]", "delete the resources in the file"
|
111
91
|
long_desc <<-LONGDESC
|
112
|
-
`
|
113
|
-
\x5`
|
92
|
+
`xapixctl delete -f FILE` will delete all the resources listed in the file.
|
93
|
+
\x5`xapixctl delete TYPE ID` will delete the resource by given TYPE and ID.
|
114
94
|
|
115
95
|
The given file should be in YAML format and can contain multiple resource definitions, each as it's own YAML document.
|
96
|
+
You can also provide a directory, in which case all files with yml/yaml extension will get loaded.
|
116
97
|
You can also read from stdin by using '-'.
|
117
98
|
|
118
99
|
Examples:
|
119
|
-
\x5> $
|
120
|
-
\x5> $
|
121
|
-
\x5> $
|
100
|
+
\x5> $ xapixctl delete -o xapix Project some-project
|
101
|
+
\x5> $ xapixctl delete -p xapix -p some-project DataSource get-a-list
|
102
|
+
\x5> $ xapixctl delete -p xapix/some-project DataSource get-a-list
|
103
|
+
\x5> $ xapixctl delete -p xapix/some-project -f get_a_list.yaml
|
104
|
+
\x5> $ xapixctl delete -p xapix/some-project -f ./
|
122
105
|
LONGDESC
|
123
106
|
def delete(resource_type = nil, resource_id = nil)
|
124
107
|
if resource_type && resource_id
|
125
|
-
|
126
|
-
|
127
|
-
res.on_error { |err, result| warn_api_error("could not delete", err, result) }
|
128
|
-
end
|
108
|
+
org_or_prj_connection.delete(resource_type, resource_id)
|
109
|
+
puts "DELETED #{resource_type} #{resource_id}"
|
129
110
|
elsif options[:file]
|
130
|
-
resources_from_file(options[:file]) do |desc|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
connection.delete(type, id, org: options[:org], project: options[:project]) do |res|
|
135
|
-
res.on_success { puts "DELETED #{type} #{id}" }
|
136
|
-
res.on_error { |err, result| warn_api_error("could not delete", err, result); break }
|
137
|
-
end
|
111
|
+
Util.resources_from_file(options[:file]) do |desc|
|
112
|
+
res_type = desc['kind']
|
113
|
+
res_id = desc.dig('metadata', 'id')
|
114
|
+
delete(res_type, res_id)
|
138
115
|
end
|
139
116
|
else
|
140
117
|
warn "need TYPE and ID or --file option"
|
141
118
|
end
|
142
119
|
end
|
143
120
|
|
144
|
-
option :org, aliases: "-o", desc: "Organization", required: true
|
145
|
-
option :project, aliases: "-p", desc: "Project", required: true
|
146
121
|
desc "publish", "Publishes the current version of the given project"
|
147
122
|
long_desc <<-LONGDESC
|
148
|
-
`
|
123
|
+
`xapixctl publish` will publish the given project.
|
149
124
|
|
150
125
|
Examples:
|
151
|
-
\x5> $
|
126
|
+
\x5> $ xapixctl publish -o xapix -p some-project
|
127
|
+
\x5> $ xapixctl publish -p xapix/some-project
|
152
128
|
LONGDESC
|
153
129
|
def publish
|
154
|
-
|
130
|
+
prj_connection.publish do |res|
|
155
131
|
res.on_success { |result| show_deployment_status(result) }
|
156
|
-
res.on_error { |err, result| show_deployment_status(result);
|
132
|
+
res.on_error { |err, result| show_deployment_status(result); exit_with_api_error(err, result) }
|
157
133
|
end
|
158
134
|
end
|
159
135
|
|
160
|
-
option :org, aliases: "-o", desc: "Organization", required: true
|
161
|
-
option :project, aliases: "-p", desc: "Project", required: true
|
162
136
|
desc "logs CORRELATION_ID", "Retrieves the execution logs for the given correlation ID"
|
163
137
|
long_desc <<-LONGDESC
|
164
|
-
`
|
138
|
+
`xapixctl logs CORRELATION_ID` will retrieve execution logs for the given correlation ID.
|
165
139
|
|
166
140
|
The correlation ID is included as X-Correlation-Id header in the response of each request.
|
167
141
|
|
168
142
|
Examples:
|
169
|
-
\x5> $
|
143
|
+
\x5> $ xapixctl logs be9c8608-e291-460d-bc20-5a394c4079d4 -o xapix -p some-project
|
144
|
+
\x5> $ xapixctl logs be9c8608-e291-460d-bc20-5a394c4079d4 -p xapix/some-project
|
170
145
|
LONGDESC
|
171
146
|
def logs(correlation_id)
|
172
|
-
|
173
|
-
|
174
|
-
res.on_error { |err, result| warn_api_error('could not get logs', err, result) }
|
175
|
-
end
|
147
|
+
result = prj_connection.logs(correlation_id)
|
148
|
+
puts result['logs'].to_yaml
|
176
149
|
end
|
177
150
|
|
178
151
|
SUPPORTED_CONTEXTS = ['Project', 'Organization'].freeze
|
152
|
+
|
179
153
|
desc "api-resources", "retrieves a list of all available resource types"
|
180
154
|
def api_resources
|
181
|
-
connection.available_resource_types
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
puts format_str % [desc['type'], desc['context']]
|
188
|
-
end
|
189
|
-
end
|
190
|
-
res.on_error { |err, result| warn_api_error("could not get", err, result) }
|
155
|
+
available_types = connection.available_resource_types
|
156
|
+
format_str = "%20.20s %20.20s %26.26s"
|
157
|
+
puts format_str % ['Type', 'Required Context', '']
|
158
|
+
available_types.sort_by { |desc| desc['type'] }.each do |desc|
|
159
|
+
next unless SUPPORTED_CONTEXTS.include?(desc['context'])
|
160
|
+
puts format_str % [desc['type'], desc['context'], PhoenixClient.supported_type?(desc['type']) ? '' : '(unsupported, update CLI)']
|
191
161
|
end
|
192
162
|
end
|
193
|
-
|
194
|
-
private
|
195
|
-
|
196
|
-
def warn_api_error(text, err, result)
|
197
|
-
details = "\n " + result['errors'].map { |k| k['detail'] }.join("\n ") rescue err.to_s
|
198
|
-
warn "#{text}: #{details}"
|
199
|
-
exit 1
|
200
|
-
end
|
201
|
-
|
202
|
-
def show_deployment_status(result)
|
203
|
-
return unless result && result['project_publication']
|
204
|
-
puts "deployment: #{result.dig('project_publication', 'deployment')}"
|
205
|
-
puts " data api: #{result.dig('project_publication', 'data_api')} (version: #{result.dig('project_publication', 'data_api_version').presence || 'n/a'})"
|
206
|
-
puts " user management: #{result.dig('project_publication', 'user_management')}"
|
207
|
-
if result.dig('project_publication', 'deployment') == 'success'
|
208
|
-
puts " base URL: #{result.dig('project_publication', 'base_url')}"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
DOCUMENT_STRUCTURE = %w[version kind metadata definition].freeze
|
213
|
-
def resources_from_file(filename)
|
214
|
-
yaml_string = filename == '-' ? $stdin.read : IO.read(filename)
|
215
|
-
yaml_string.split(/^---\s*\n/).map { |yml| Psych.safe_load(yml) }.compact.each do |doc|
|
216
|
-
unless (DOCUMENT_STRUCTURE - doc.keys.map(&:to_s)).empty?
|
217
|
-
warn "does not look like a correct resource definition:"
|
218
|
-
warn doc.inspect
|
219
|
-
exit 1
|
220
|
-
end
|
221
|
-
yield doc
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
def connection
|
226
|
-
url = options[:xapix_url] || ENV['XAPIX_URL'] || 'https://cloud.xapix.io/'
|
227
|
-
token = options[:xapix_token] || ENV['XAPIX_TOKEN']
|
228
|
-
raise Thor::RequiredArgumentMissingError, "no XAPIX_TOKEN given. Either use --xapix_token [TOKEN] or set environment variable XAPIX_TOKEN (recommended)" if !token
|
229
|
-
PhoenixClient::Connection.new(url, token)
|
230
|
-
end
|
231
163
|
end
|
232
164
|
end
|