xapixctl 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9f36513c3a71e1c789c1438f4aca2aa84b5c21a15fc5a415e0d048ec24342a35
4
+ data.tar.gz: '08fe973118fec5ac856092f1e6588d7b0ff3fefbe48843e6b739e33dec8e3d67'
5
+ SHA512:
6
+ metadata.gz: a305bf7036a9f2a562750cd6bcb0ca4aa8e75017d4b21dbbacbd82580857890438af8162e0779bc4d3d35e0c7e131a0e0616bf1c9cdbf6a56afa819bbfa87f1d
7
+ data.tar.gz: dda3172f38b678db380907b828c4813091219b264e5d4f38b084691eb1efb88f05d755216234a6a12e97cdb432fbd5983df62f64f842d226864ffcd95c06ef49
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ # rvm and other tools
14
+ .ruby-gemset
15
+ .envrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,27 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ DisplayCopNames: true
4
+ Exclude:
5
+ - bin/*
6
+
7
+ inherit_gem:
8
+ relaxed-rubocop: .rubocop.yml
9
+
10
+ Documentation:
11
+ Enabled: false
12
+
13
+ Metrics/LineLength:
14
+ Max: 120
15
+
16
+ Layout/EmptyLineAfterGuardClause:
17
+ Enabled: false
18
+
19
+ Layout/MultilineOperationIndentation:
20
+ EnforcedStyle: indented
21
+
22
+ Style/OptionHash:
23
+ Enabled: true
24
+
25
+ Metrics/BlockLength:
26
+ Exclude:
27
+ - spec/**/*
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in xapixctl.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ xapixctl (1.0.0)
5
+ activesupport (~> 5.2.3)
6
+ rest-client (~> 2.1.0)
7
+ thor (~> 0.20.3)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (5.2.4.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ ast (2.4.0)
18
+ concurrent-ruby (1.1.5)
19
+ diff-lcs (1.3)
20
+ domain_name (0.5.20190701)
21
+ unf (>= 0.0.5, < 1.0.0)
22
+ http-accept (1.7.0)
23
+ http-cookie (1.0.3)
24
+ domain_name (~> 0.5)
25
+ i18n (1.8.2)
26
+ concurrent-ruby (~> 1.0)
27
+ jaro_winkler (1.5.4)
28
+ mime-types (3.3.1)
29
+ mime-types-data (~> 3.2015)
30
+ mime-types-data (3.2019.1009)
31
+ minitest (5.14.0)
32
+ netrc (0.11.0)
33
+ parallel (1.19.1)
34
+ parser (2.7.0.2)
35
+ ast (~> 2.4.0)
36
+ rainbow (3.0.0)
37
+ rake (10.5.0)
38
+ relaxed-rubocop (2.5)
39
+ rest-client (2.1.0)
40
+ http-accept (>= 1.7.0, < 2.0)
41
+ http-cookie (>= 1.0.2, < 2.0)
42
+ mime-types (>= 1.16, < 4.0)
43
+ netrc (~> 0.8)
44
+ rspec (3.9.0)
45
+ rspec-core (~> 3.9.0)
46
+ rspec-expectations (~> 3.9.0)
47
+ rspec-mocks (~> 3.9.0)
48
+ rspec-core (3.9.1)
49
+ rspec-support (~> 3.9.1)
50
+ rspec-expectations (3.9.0)
51
+ diff-lcs (>= 1.2.0, < 2.0)
52
+ rspec-support (~> 3.9.0)
53
+ rspec-mocks (3.9.1)
54
+ diff-lcs (>= 1.2.0, < 2.0)
55
+ rspec-support (~> 3.9.0)
56
+ rspec-support (3.9.2)
57
+ rubocop (0.79.0)
58
+ jaro_winkler (~> 1.5.1)
59
+ parallel (~> 1.10)
60
+ parser (>= 2.7.0.1)
61
+ rainbow (>= 2.2.2, < 4.0)
62
+ ruby-progressbar (~> 1.7)
63
+ unicode-display_width (>= 1.4.0, < 1.7)
64
+ ruby-progressbar (1.10.1)
65
+ thor (0.20.3)
66
+ thread_safe (0.3.6)
67
+ tzinfo (1.2.6)
68
+ thread_safe (~> 0.1)
69
+ unf (0.1.4)
70
+ unf_ext
71
+ unf_ext (0.0.7.6)
72
+ unicode-display_width (1.6.1)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ bundler (~> 1.17.3)
79
+ rake (~> 10.0)
80
+ relaxed-rubocop (~> 2.5)
81
+ rspec (~> 3.0)
82
+ rubocop (~> 0.79.0)
83
+ xapixctl!
84
+
85
+ BUNDLED WITH
86
+ 1.17.3
data/LICENSE ADDED
@@ -0,0 +1,277 @@
1
+ Eclipse Public License - v 2.0
2
+
3
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
4
+ PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
5
+ OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6
+
7
+ 1. DEFINITIONS
8
+
9
+ "Contribution" means:
10
+
11
+ a) in the case of the initial Contributor, the initial content
12
+ Distributed under this Agreement, and
13
+
14
+ b) in the case of each subsequent Contributor:
15
+ i) changes to the Program, and
16
+ ii) additions to the Program;
17
+ where such changes and/or additions to the Program originate from
18
+ and are Distributed by that particular Contributor. A Contribution
19
+ "originates" from a Contributor if it was added to the Program by
20
+ such Contributor itself or anyone acting on such Contributor's behalf.
21
+ Contributions do not include changes or additions to the Program that
22
+ are not Modified Works.
23
+
24
+ "Contributor" means any person or entity that Distributes the Program.
25
+
26
+ "Licensed Patents" mean patent claims licensable by a Contributor which
27
+ are necessarily infringed by the use or sale of its Contribution alone
28
+ or when combined with the Program.
29
+
30
+ "Program" means the Contributions Distributed in accordance with this
31
+ Agreement.
32
+
33
+ "Recipient" means anyone who receives the Program under this Agreement
34
+ or any Secondary License (as applicable), including Contributors.
35
+
36
+ "Derivative Works" shall mean any work, whether in Source Code or other
37
+ form, that is based on (or derived from) the Program and for which the
38
+ editorial revisions, annotations, elaborations, or other modifications
39
+ represent, as a whole, an original work of authorship.
40
+
41
+ "Modified Works" shall mean any work in Source Code or other form that
42
+ results from an addition to, deletion from, or modification of the
43
+ contents of the Program, including, for purposes of clarity any new file
44
+ in Source Code form that contains any contents of the Program. Modified
45
+ Works shall not include works that contain only declarations,
46
+ interfaces, types, classes, structures, or files of the Program solely
47
+ in each case in order to link to, bind by name, or subclass the Program
48
+ or Modified Works thereof.
49
+
50
+ "Distribute" means the acts of a) distributing or b) making available
51
+ in any manner that enables the transfer of a copy.
52
+
53
+ "Source Code" means the form of a Program preferred for making
54
+ modifications, including but not limited to software source code,
55
+ documentation source, and configuration files.
56
+
57
+ "Secondary License" means either the GNU General Public License,
58
+ Version 2.0, or any later versions of that license, including any
59
+ exceptions or additional permissions as identified by the initial
60
+ Contributor.
61
+
62
+ 2. GRANT OF RIGHTS
63
+
64
+ a) Subject to the terms of this Agreement, each Contributor hereby
65
+ grants Recipient a non-exclusive, worldwide, royalty-free copyright
66
+ license to reproduce, prepare Derivative Works of, publicly display,
67
+ publicly perform, Distribute and sublicense the Contribution of such
68
+ Contributor, if any, and such Derivative Works.
69
+
70
+ b) Subject to the terms of this Agreement, each Contributor hereby
71
+ grants Recipient a non-exclusive, worldwide, royalty-free patent
72
+ license under Licensed Patents to make, use, sell, offer to sell,
73
+ import and otherwise transfer the Contribution of such Contributor,
74
+ if any, in Source Code or other form. This patent license shall
75
+ apply to the combination of the Contribution and the Program if, at
76
+ the time the Contribution is added by the Contributor, such addition
77
+ of the Contribution causes such combination to be covered by the
78
+ Licensed Patents. The patent license shall not apply to any other
79
+ combinations which include the Contribution. No hardware per se is
80
+ licensed hereunder.
81
+
82
+ c) Recipient understands that although each Contributor grants the
83
+ licenses to its Contributions set forth herein, no assurances are
84
+ provided by any Contributor that the Program does not infringe the
85
+ patent or other intellectual property rights of any other entity.
86
+ Each Contributor disclaims any liability to Recipient for claims
87
+ brought by any other entity based on infringement of intellectual
88
+ property rights or otherwise. As a condition to exercising the
89
+ rights and licenses granted hereunder, each Recipient hereby
90
+ assumes sole responsibility to secure any other intellectual
91
+ property rights needed, if any. For example, if a third party
92
+ patent license is required to allow Recipient to Distribute the
93
+ Program, it is Recipient's responsibility to acquire that license
94
+ before distributing the Program.
95
+
96
+ d) Each Contributor represents that to its knowledge it has
97
+ sufficient copyright rights in its Contribution, if any, to grant
98
+ the copyright license set forth in this Agreement.
99
+
100
+ e) Notwithstanding the terms of any Secondary License, no
101
+ Contributor makes additional grants to any Recipient (other than
102
+ those set forth in this Agreement) as a result of such Recipient's
103
+ receipt of the Program under the terms of a Secondary License
104
+ (if permitted under the terms of Section 3).
105
+
106
+ 3. REQUIREMENTS
107
+
108
+ 3.1 If a Contributor Distributes the Program in any form, then:
109
+
110
+ a) the Program must also be made available as Source Code, in
111
+ accordance with section 3.2, and the Contributor must accompany
112
+ the Program with a statement that the Source Code for the Program
113
+ is available under this Agreement, and informs Recipients how to
114
+ obtain it in a reasonable manner on or through a medium customarily
115
+ used for software exchange; and
116
+
117
+ b) the Contributor may Distribute the Program under a license
118
+ different than this Agreement, provided that such license:
119
+ i) effectively disclaims on behalf of all other Contributors all
120
+ warranties and conditions, express and implied, including
121
+ warranties or conditions of title and non-infringement, and
122
+ implied warranties or conditions of merchantability and fitness
123
+ for a particular purpose;
124
+
125
+ ii) effectively excludes on behalf of all other Contributors all
126
+ liability for damages, including direct, indirect, special,
127
+ incidental and consequential damages, such as lost profits;
128
+
129
+ iii) does not attempt to limit or alter the recipients' rights
130
+ in the Source Code under section 3.2; and
131
+
132
+ iv) requires any subsequent distribution of the Program by any
133
+ party to be under a license that satisfies the requirements
134
+ of this section 3.
135
+
136
+ 3.2 When the Program is Distributed as Source Code:
137
+
138
+ a) it must be made available under this Agreement, or if the
139
+ Program (i) is combined with other material in a separate file or
140
+ files made available under a Secondary License, and (ii) the initial
141
+ Contributor attached to the Source Code the notice described in
142
+ Exhibit A of this Agreement, then the Program may be made available
143
+ under the terms of such Secondary Licenses, and
144
+
145
+ b) a copy of this Agreement must be included with each copy of
146
+ the Program.
147
+
148
+ 3.3 Contributors may not remove or alter any copyright, patent,
149
+ trademark, attribution notices, disclaimers of warranty, or limitations
150
+ of liability ("notices") contained within the Program from any copy of
151
+ the Program which they Distribute, provided that Contributors may add
152
+ their own appropriate notices.
153
+
154
+ 4. COMMERCIAL DISTRIBUTION
155
+
156
+ Commercial distributors of software may accept certain responsibilities
157
+ with respect to end users, business partners and the like. While this
158
+ license is intended to facilitate the commercial use of the Program,
159
+ the Contributor who includes the Program in a commercial product
160
+ offering should do so in a manner which does not create potential
161
+ liability for other Contributors. Therefore, if a Contributor includes
162
+ the Program in a commercial product offering, such Contributor
163
+ ("Commercial Contributor") hereby agrees to defend and indemnify every
164
+ other Contributor ("Indemnified Contributor") against any losses,
165
+ damages and costs (collectively "Losses") arising from claims, lawsuits
166
+ and other legal actions brought by a third party against the Indemnified
167
+ Contributor to the extent caused by the acts or omissions of such
168
+ Commercial Contributor in connection with its distribution of the Program
169
+ in a commercial product offering. The obligations in this section do not
170
+ apply to any claims or Losses relating to any actual or alleged
171
+ intellectual property infringement. In order to qualify, an Indemnified
172
+ Contributor must: a) promptly notify the Commercial Contributor in
173
+ writing of such claim, and b) allow the Commercial Contributor to control,
174
+ and cooperate with the Commercial Contributor in, the defense and any
175
+ related settlement negotiations. The Indemnified Contributor may
176
+ participate in any such claim at its own expense.
177
+
178
+ For example, a Contributor might include the Program in a commercial
179
+ product offering, Product X. That Contributor is then a Commercial
180
+ Contributor. If that Commercial Contributor then makes performance
181
+ claims, or offers warranties related to Product X, those performance
182
+ claims and warranties are such Commercial Contributor's responsibility
183
+ alone. Under this section, the Commercial Contributor would have to
184
+ defend claims against the other Contributors related to those performance
185
+ claims and warranties, and if a court requires any other Contributor to
186
+ pay any damages as a result, the Commercial Contributor must pay
187
+ those damages.
188
+
189
+ 5. NO WARRANTY
190
+
191
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
192
+ PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
193
+ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
194
+ IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
195
+ TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
196
+ PURPOSE. Each Recipient is solely responsible for determining the
197
+ appropriateness of using and distributing the Program and assumes all
198
+ risks associated with its exercise of rights under this Agreement,
199
+ including but not limited to the risks and costs of program errors,
200
+ compliance with applicable laws, damage to or loss of data, programs
201
+ or equipment, and unavailability or interruption of operations.
202
+
203
+ 6. DISCLAIMER OF LIABILITY
204
+
205
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
206
+ PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
207
+ SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
208
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
209
+ PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
210
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
211
+ ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
212
+ EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
213
+ POSSIBILITY OF SUCH DAMAGES.
214
+
215
+ 7. GENERAL
216
+
217
+ If any provision of this Agreement is invalid or unenforceable under
218
+ applicable law, it shall not affect the validity or enforceability of
219
+ the remainder of the terms of this Agreement, and without further
220
+ action by the parties hereto, such provision shall be reformed to the
221
+ minimum extent necessary to make such provision valid and enforceable.
222
+
223
+ If Recipient institutes patent litigation against any entity
224
+ (including a cross-claim or counterclaim in a lawsuit) alleging that the
225
+ Program itself (excluding combinations of the Program with other software
226
+ or hardware) infringes such Recipient's patent(s), then such Recipient's
227
+ rights granted under Section 2(b) shall terminate as of the date such
228
+ litigation is filed.
229
+
230
+ All Recipient's rights under this Agreement shall terminate if it
231
+ fails to comply with any of the material terms or conditions of this
232
+ Agreement and does not cure such failure in a reasonable period of
233
+ time after becoming aware of such noncompliance. If all Recipient's
234
+ rights under this Agreement terminate, Recipient agrees to cease use
235
+ and distribution of the Program as soon as reasonably practicable.
236
+ However, Recipient's obligations under this Agreement and any licenses
237
+ granted by Recipient relating to the Program shall continue and survive.
238
+
239
+ Everyone is permitted to copy and distribute copies of this Agreement,
240
+ but in order to avoid inconsistency the Agreement is copyrighted and
241
+ may only be modified in the following manner. The Agreement Steward
242
+ reserves the right to publish new versions (including revisions) of
243
+ this Agreement from time to time. No one other than the Agreement
244
+ Steward has the right to modify this Agreement. The Eclipse Foundation
245
+ is the initial Agreement Steward. The Eclipse Foundation may assign the
246
+ responsibility to serve as the Agreement Steward to a suitable separate
247
+ entity. Each new version of the Agreement will be given a distinguishing
248
+ version number. The Program (including Contributions) may always be
249
+ Distributed subject to the version of the Agreement under which it was
250
+ received. In addition, after a new version of the Agreement is published,
251
+ Contributor may elect to Distribute the Program (including its
252
+ Contributions) under the new version.
253
+
254
+ Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
255
+ receives no rights or licenses to the intellectual property of any
256
+ Contributor under this Agreement, whether expressly, by implication,
257
+ estoppel or otherwise. All rights in the Program not expressly granted
258
+ under this Agreement are reserved. Nothing in this Agreement is intended
259
+ to be enforceable by any entity that is not a Contributor or Recipient.
260
+ No third-party beneficiary rights are created under this Agreement.
261
+
262
+ Exhibit A - Form of Secondary Licenses Notice
263
+
264
+ "This Source Code may also be made available under the following
265
+ Secondary Licenses when the conditions for such availability set forth
266
+ in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
267
+ version(s), and exceptions or additional permissions here}."
268
+
269
+ Simply including a copy of this Agreement, including this Exhibit A
270
+ is not sufficient to license the Source Code under Secondary Licenses.
271
+
272
+ If it is not possible or desirable to put the notice in a particular
273
+ file, then You may include the notice in a location (such as a LICENSE
274
+ file in a relevant directory) where a recipient would be likely to
275
+ look for such a notice.
276
+
277
+ You may add additional accurate notices of copyright ownership.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # xapixctl
2
+
3
+ Xapix client library and command line tool
4
+
5
+ ## Installation
6
+
7
+ Install it via:
8
+
9
+ $ gem install xapixctl
10
+
11
+ ## Usage
12
+
13
+ To see more details on how to run xapixctl, use:
14
+
15
+ ```
16
+ $ xapixctl help
17
+
18
+ Commands:
19
+ xapixctl api-resources # retrieves a list of all available resource types
20
+ xapixctl apply -f, --file=FILE -o, --org=ORG # Create or update a resource from a file
21
+ xapixctl delete [TYPE ID] [-f FILE] -o, --org=ORG # delete the resources in the file
22
+ xapixctl export -o, --org=ORG -p, --project=PROJECT # retrieves all resources within a project
23
+ xapixctl get TYPE [ID] -o, --org=ORG # retrieve either all resources of given TYPE or just the resource of given TYPE and ID
24
+ xapixctl help [COMMAND] # Describe available commands or one specific command
25
+ xapixctl logs CORRELATION_ID -o, --org=ORG -p, --project=PROJECT # Retrieves the execution logs for the given correlation ID
26
+ xapixctl publish -o, --org=ORG -p, --project=PROJECT # Publishes the current version of the given project
27
+
28
+ Options:
29
+ -v, [--verbose], [--no-verbose]
30
+ [--xapix-url=XAPIX_URL] # Fallback: environment variable XAPIX_URL. URL to Xapix. Default: https://cloud.xapix.io/
31
+ [--xapix-token=XAPIX_TOKEN] # Fallback: environment variable XAPIX_TOKEN. Your access token.
32
+ ```
33
+
34
+ The main commands to interact with Xapix are:
35
+ * `xapixctl get TYPE` to list all the resources of a specific type. You can get the supported types with `xapixctl api-resources`. To see the complete resource definition instead of an overview use the `-f yaml` switch. Use `xapixctl help get` for more details.
36
+ * `xapixctl apply` to create a new resource or update existing ones. Resources are matched using their type and id. If a resource with the same type and id already exists it is updated, otherwise a new one is created.
37
+ * `xapixctl publish` to publish the current status of a project.
38
+
39
+
40
+ ## Development
41
+
42
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
43
+
44
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
+
46
+ ## Contributing
47
+
48
+ Bug reports and pull requests are welcome on GitHub at https://github.com/xapix-io/xapixctl.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "xapixctl"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/xapixctl ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "xapixctl"
5
+ require "xapixctl/cli"
6
+
7
+ Xapixctl::Cli.start(ARGV)
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Xapixctl
6
+ class Cli < Thor
7
+ def self.exit_on_failure?; true; end
8
+
9
+ class_option :verbose, type: :boolean, aliases: "-v"
10
+ class_option :xapix_url, desc: "Fallback: environment variable XAPIX_URL. URL to Xapix. Default: https://cloud.xapix.io/"
11
+ class_option :xapix_token, desc: "Fallback: environment variable XAPIX_TOKEN. Your access token."
12
+
13
+ option :org, aliases: "-o", desc: "Organization", required: true
14
+ option :project, aliases: "-p", desc: "Project"
15
+ option :format, aliases: "-f", default: 'text', enum: ['text', 'yaml', 'json'], desc: "Output format"
16
+ desc "get TYPE [ID]", "retrieve either all resources of given TYPE or just the resource of given TYPE and ID"
17
+ long_desc <<-LONGDESC
18
+ `xapctl get TYPE` will retrieve the list of all resources of given type.
19
+
20
+ If requested on an organization (i.e. no project given), the following types are available:
21
+ \x5 Project
22
+
23
+ If requested on an a project (i.e. organization and project are given), the following types are available:
24
+ \x5 Ambassador, AuthScheme, CacheConnection, Credential, DataSource, Endpoint, EndpointGroup, Proxy, Schema, Stream, StreamGroup
25
+
26
+ Use the format to switch between the different output formats.
27
+
28
+ Examples:
29
+ \x5> $ xapctl get -o xapix Project
30
+ \x5> $ xapctl get -o xapix Project some-project
31
+ \x5> $ xapctl get -o xapix -p some-project DataSource
32
+ \x5> $ xapctl get -o xapix -p some-project DataSource get-a-list
33
+ LONGDESC
34
+ def get(resource_type, resource_id = nil)
35
+ if resource_id
36
+ connection.resource(resource_type, resource_id, org: options[:org], project: options[:project], format: options[:format].to_sym) do |res|
37
+ res.on_success { |resource| puts resource }
38
+ res.on_error { |err, result| warn_api_error("could not get", err, result) }
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
52
+ end
53
+ end
54
+
55
+ option :org, aliases: "-o", desc: "Organization", required: true
56
+ option :project, aliases: "-p", desc: "Project", required: true
57
+ option :format, aliases: "-f", default: 'text', enum: ['text', 'yaml', 'json'], desc: "Output format"
58
+ desc "export", "retrieves all resources within a project"
59
+ long_desc <<-LONGDESC
60
+ `xapctl export` will retrieve the list of all resources of given type.
61
+
62
+ Use the format to switch between the different output formats.
63
+
64
+ Examples:
65
+ \x5> $ xapctl export -o xapix -p some-project
66
+ \x5> $ xapctl export -o xapix -p some-project -f yaml > some_project.yaml
67
+ LONGDESC
68
+ def export
69
+ connection.resource('Project', options[:project], org: options[:org], format: options[:format].to_sym) do |res|
70
+ res.on_success { |resource| puts resource }
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) }
74
+ end
75
+
76
+ option :org, aliases: "-o", desc: "Organization", required: true
77
+ option :project, aliases: "-p", desc: "Project"
78
+ option :file, aliases: "-f", required: true
79
+ desc "apply", "Create or update a resource from a file"
80
+ long_desc <<-LONGDESC
81
+ `xapctl apply -f FILE` will apply the given resource description.
82
+
83
+ If applied on an organization (i.e. no project given), the project is taken from the resource description.
84
+
85
+ If applied on a project (i.e. organization and project are given), the given project is used.
86
+
87
+ The given file should be in YAML format and can contain multiple resource definitions, each as it's own YAML document.
88
+ You can also read from stdin by using '-'.
89
+
90
+ Examples:
91
+ \x5> $ xapctl apply -o xapix -f get_a_list.yaml
92
+ \x5> $ xapctl apply -o xapix -p some-project -f get_a_list.yaml
93
+
94
+ To copy over all data sources from one project to another:
95
+ \x5> $ xapctl get -o xapix-old -p some-project DataSource -f yaml | xapctl apply -o xapix-new -f -
96
+ LONGDESC
97
+ def apply
98
+ resources_from_file(options[:file]) do |desc|
99
+ puts "applying #{desc['kind']} #{desc.dig('metadata', 'id')}"
100
+ connection.apply(desc, org: options[:org], project: options[:project]) do |res|
101
+ res.on_success { puts 'OK' }
102
+ res.on_error { |err, result| warn_api_error("could not apply changes", err, result); break }
103
+ end
104
+ end
105
+ end
106
+
107
+ option :org, aliases: "-o", desc: "Organization", required: true
108
+ option :project, aliases: "-p", desc: "Project"
109
+ option :file, aliases: "-f"
110
+ desc "delete [TYPE ID] [-f FILE]", "delete the resources in the file"
111
+ long_desc <<-LONGDESC
112
+ `xapctl delete -f FILE` will delete all the resources listed in the file.
113
+ \x5`xapctl delete TYPE ID` will delete the resource by given TYPE and ID.
114
+
115
+ The given file should be in YAML format and can contain multiple resource definitions, each as it's own YAML document.
116
+ You can also read from stdin by using '-'.
117
+
118
+ Examples:
119
+ \x5> $ xapctl delete -o xapix -p some-project -f get_a_list.yaml
120
+ \x5> $ xapctl delete -o xapix -p some-project DataSource get-a-list
121
+ \x5> $ xapctl delete -o xapix Project some-project
122
+ LONGDESC
123
+ def delete(resource_type = nil, resource_id = nil)
124
+ if resource_type && resource_id
125
+ connection.delete(resource_type, resource_id, org: options[:org], project: options[:project]) do |res|
126
+ res.on_success { puts 'DELETED' }
127
+ res.on_error { |err, result| warn_api_error("could not delete", err, result) }
128
+ end
129
+ elsif options[:file]
130
+ resources_from_file(options[:file]) do |desc|
131
+ type = desc.dig('kind')
132
+ id = desc.dig('metadata', 'id')
133
+ puts "deleting #{type} #{id}"
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
138
+ end
139
+ else
140
+ warn "need TYPE and ID or --file option"
141
+ end
142
+ end
143
+
144
+ option :org, aliases: "-o", desc: "Organization", required: true
145
+ option :project, aliases: "-p", desc: "Project", required: true
146
+ desc "publish", "Publishes the current version of the given project"
147
+ long_desc <<-LONGDESC
148
+ `xapctl publish` will publish the given project.
149
+
150
+ Examples:
151
+ \x5> $ xapctl publish -o xapix -p some-project
152
+ LONGDESC
153
+ def publish
154
+ connection.publish(org: options[:org], project: options[:project]) do |res|
155
+ res.on_success { |result| show_deployment_status(result) }
156
+ res.on_error { |err, result| show_deployment_status(result); warn_api_error('errors', err, result) }
157
+ end
158
+ end
159
+
160
+ option :org, aliases: "-o", desc: "Organization", required: true
161
+ option :project, aliases: "-p", desc: "Project", required: true
162
+ desc "logs CORRELATION_ID", "Retrieves the execution logs for the given correlation ID"
163
+ long_desc <<-LONGDESC
164
+ `xapctl logs CORRELATION_ID` will retrieve execution logs for the given correlation ID.
165
+
166
+ The correlation ID is included as X-Correlation-Id header in the response of each request.
167
+
168
+ Examples:
169
+ \x5> $ xapctl logs be9c8608-e291-460d-bc20-5a394c4079d4 -o xapix -p some-project
170
+ LONGDESC
171
+ def logs(correlation_id)
172
+ connection.logs(correlation_id, org: options[:org], project: options[:project]) do |res|
173
+ res.on_success { |result| puts result['logs'].to_yaml }
174
+ res.on_error { |err, result| warn_api_error('could not get logs', err, result) }
175
+ end
176
+ end
177
+
178
+ SUPPORTED_CONTEXTS = ['Project', 'Organization'].freeze
179
+ desc "api-resources", "retrieves a list of all available resource types"
180
+ def api_resources
181
+ connection.available_resource_types do |res|
182
+ res.on_success do |available_types|
183
+ format_str = "%20.20s %20.20s"
184
+ puts format_str % ['Type', 'Required Context']
185
+ available_types.sort_by { |desc| desc['type'] }.each do |desc|
186
+ next unless SUPPORTED_CONTEXTS.include?(desc['context'])
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) }
191
+ end
192
+ 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
+ end
232
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xapixctl
4
+ module PhoenixClient
5
+
6
+ class ResultHandler
7
+ def initialize(default_success_handler:, default_error_handler:)
8
+ @success_handler = default_success_handler
9
+ @error_handler = default_error_handler
10
+ @result_handler = nil
11
+ yield self if block_given?
12
+ end
13
+
14
+ def on_success(&block); @success_handler = block; self; end
15
+
16
+ def on_error(&block); @error_handler = block; self; end
17
+
18
+ def prepare_data(proc); @result_handler = proc; self; end
19
+
20
+ def formatter(proc); @formatter = proc; self; end
21
+
22
+ def run
23
+ res = yield
24
+ res = res.present? ? JSON.parse(res) : res
25
+ res = @result_handler ? @result_handler.call(res) : res
26
+ res = @formatter ? @formatter.call(res) : res
27
+ @success_handler.call(res)
28
+ rescue RestClient::Exception => err
29
+ response = JSON.parse(err.response) rescue {}
30
+ @error_handler.call(err, response)
31
+ rescue SocketError, Errno::ECONNREFUSED => err
32
+ @error_handler.call(err, nil)
33
+ end
34
+ end
35
+
36
+ TEXT_FORMATTERS = {
37
+ all: ->(data) { "id : %{id}\nkind: %{kind}\nname: %{name}\n\n" % { id: data.dig('metadata', 'id'), kind: data.dig('kind'), name: data.dig('definition', 'name') } }
38
+ }.freeze
39
+
40
+ FORMATTERS = {
41
+ json: ->(data) { JSON.pretty_generate(data) },
42
+ yaml: ->(data) { Psych.dump(data.deep_transform_keys! { |k| k.to_s.camelize(:lower) }) },
43
+ text: ->(data) { (TEXT_FORMATTERS[data.dig('metadata', 'type')] || TEXT_FORMATTERS[:all]).call(data) }
44
+ }.freeze
45
+
46
+ class Connection
47
+ DEFAULT_SUCCESS_HANDLER = ->(result) { result }
48
+ DEFAULT_ERROR_HANDLER = ->(err, _response) { warn "Could not get data: #{err}" }
49
+
50
+ # sorting is intentional to reflect dependencies when exporting
51
+ SUPPORTED_RESOURCE_TYPES = %w[
52
+ Project
53
+ Ambassador
54
+ AuthScheme
55
+ Credential
56
+ Proxy
57
+ CacheConnection
58
+ Schema
59
+ DataSource
60
+ Pipeline
61
+ EndpointGroup
62
+ Endpoint
63
+ StreamGroup
64
+ Stream
65
+ ApiPublishing
66
+ ApiPublishingRole
67
+ ].freeze
68
+
69
+ def initialize(url, token)
70
+ @client = RestClient::Resource.new(File.join(url, 'api/v1'), verify_ssl: false, accept: :json, content_type: :json, headers: { Authorization: "Bearer #{token}" })
71
+ @default_success_handler = DEFAULT_SUCCESS_HANDLER
72
+ @default_error_handler = DEFAULT_ERROR_HANDLER
73
+ end
74
+
75
+ def on_success(&block); @default_success_handler = block; self; end
76
+
77
+ def on_error(&block); @default_error_handler = block; self; end
78
+
79
+ def resource(resource_type, resource_id, org:, project: nil, format: :hash, &block)
80
+ result_handler(block).
81
+ formatter(FORMATTERS[format]).
82
+ run { @client[resource_path(org, project, resource_type, resource_id)].get }
83
+ end
84
+
85
+ def resource_ids(resource_type, org:, project: nil, &block)
86
+ result_handler(block).
87
+ prepare_data(->(data) { data['resource_ids'] }).
88
+ run { @client[resources_path(org, project, resource_type)].get }
89
+ end
90
+
91
+ def apply(resource_description, org:, project: nil, &block)
92
+ result_handler(block).
93
+ run { @client[generic_resource_path(org, project)].put(resource_description.to_json) }
94
+ end
95
+
96
+ def delete(resource_type, resource_id, org:, project: nil, &block)
97
+ result_handler(block).
98
+ run { @client[resource_path(org, project, resource_type, resource_id)].delete }
99
+ end
100
+
101
+ def publish(org:, project:, &block)
102
+ result_handler(block).
103
+ run { @client[project_publications_path(org, project)].post('') }
104
+ end
105
+
106
+ def logs(correlation_id, org:, project:, &block)
107
+ result_handler(block).
108
+ run { @client[project_logss_path(org, project, correlation_id)].get }
109
+ end
110
+
111
+ def available_resource_types(&block)
112
+ result_handler(block).
113
+ prepare_data(->(data) { data['resource_types'] }).
114
+ run { @client[resource_types_path].get }
115
+ end
116
+
117
+ def resource_types_for_export
118
+ @resource_types_for_export ||=
119
+ available_resource_types do |res|
120
+ res.on_success { |available_types| SUPPORTED_RESOURCE_TYPES & available_types.map { |desc| desc['type'] } }
121
+ res.on_error { |err, _response| raise err }
122
+ end
123
+ end
124
+
125
+ private
126
+
127
+ def result_handler(block)
128
+ ResultHandler.new(default_success_handler: @default_success_handler, default_error_handler: @default_error_handler, &block)
129
+ end
130
+
131
+ def resource_path(org, project, type, id)
132
+ type = translate_type(type)
133
+ project ? "/projects/#{org}/#{project}/#{type}/#{id}" : "/orgs/#{org}/#{type}/#{id}"
134
+ end
135
+
136
+ def resources_path(org, project, type)
137
+ type = translate_type(type)
138
+ project ? "/projects/#{org}/#{project}/#{type}" : "/orgs/#{org}/#{type}"
139
+ end
140
+
141
+ def generic_resource_path(org, project)
142
+ project ? "projects/#{org}/#{project}/resource" : "orgs/#{org}/resource"
143
+ end
144
+
145
+ def project_publications_path(org, project)
146
+ "/projects/#{org}/#{project}/publications"
147
+ end
148
+
149
+ def project_logss_path(org, project, correlation_id)
150
+ "/projects/#{org}/#{project}/logs/#{correlation_id}"
151
+ end
152
+
153
+ def resource_types_path
154
+ "/resource_types"
155
+ end
156
+
157
+ def translate_type(resource_type)
158
+ return 'ApiPublishingRole' if resource_type == 'ApiPublishing/Role'
159
+ resource_type.sub(%r[/.*], '') # cut off everything after first slash
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,3 @@
1
+ module Xapixctl
2
+ VERSION = "1.0.0"
3
+ end
data/lib/xapixctl.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash/keys'
5
+ require 'active_support/core_ext/object/blank'
6
+ require 'active_support/core_ext/string/inflections'
7
+ require 'rest_client'
8
+ require 'json'
9
+ require 'psych'
10
+ require 'xapixctl/version'
11
+ require 'xapixctl/phoenix_client'
12
+
13
+ module Xapixctl
14
+ end
data/xapixctl.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "xapixctl/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "xapixctl"
7
+ spec.version = Xapixctl::VERSION
8
+ spec.authors = ["Michael Reinsch"]
9
+ spec.email = ["michael@xapix.io"]
10
+
11
+ spec.summary = %q{xapix client library and command line tool}
12
+ spec.homepage = "https://github.com/xapix-io/xapixctl"
13
+ spec.license = "EPL-2.0"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = spec.homepage
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "activesupport", "~> 5.2.3"
28
+ spec.add_dependency "rest-client", "~> 2.1.0"
29
+ spec.add_dependency "thor", "~> 0.20.3"
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.17.3"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "relaxed-rubocop", "~> 2.5"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+ spec.add_development_dependency "rubocop", "~> 0.79.0"
36
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xapixctl
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Reinsch
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.20.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.20.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.17.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.17.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: relaxed-rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.79.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.79.0
125
+ description:
126
+ email:
127
+ - michael@xapix.io
128
+ executables:
129
+ - xapixctl
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".ruby-version"
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - LICENSE
140
+ - README.md
141
+ - Rakefile
142
+ - bin/console
143
+ - bin/setup
144
+ - exe/xapixctl
145
+ - lib/xapixctl.rb
146
+ - lib/xapixctl/cli.rb
147
+ - lib/xapixctl/phoenix_client.rb
148
+ - lib/xapixctl/version.rb
149
+ - xapixctl.gemspec
150
+ homepage: https://github.com/xapix-io/xapixctl
151
+ licenses:
152
+ - EPL-2.0
153
+ metadata:
154
+ homepage_uri: https://github.com/xapix-io/xapixctl
155
+ source_code_uri: https://github.com/xapix-io/xapixctl
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubygems_version: 3.0.6
172
+ signing_key:
173
+ specification_version: 4
174
+ summary: xapix client library and command line tool
175
+ test_files: []