cpl 1.1.2.rc.0 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd0eff627240313d5202ff74368af8fff67483bcf0769f52f9c923a0839bfd73
4
- data.tar.gz: a31c430587ecfce5cc1e7ede82ce31a0c91aec07de401fa849d18f75035dc4f1
3
+ metadata.gz: 89a038d31fb497bfc6c0d34451ace68fe554d700f4686413a1919cf6d9bceb09
4
+ data.tar.gz: 3c733b43e703ad7b7798cf599b71f59ea1758ce2c71babd4486670c5ed5f12a3
5
5
  SHA512:
6
- metadata.gz: 770a3ab110f7b5b7049103c50350044805ed74c1ffedf61249d9696c94877fba43cd2bef031f6d9fd2dd70f2e29e2f970cd2d32cecadd6d7a2eaa3048bd493eb
7
- data.tar.gz: ec006511deb5b41610f9d4780e02c1265eddfde523f95e3c7c373ef787039c3f5cb9a99c0132da020cd649029ea6e355b37f51fb3d4035381b10724c2ac4a4d4
6
+ metadata.gz: 325eecc73176b362c4b898632e45040544ecfdda14ecfbbd655caf92d0912aa3e431fbd8ac90c2681d4a2bcff68db0a71f80813601c1cf3b3ca32d44c9ef033f
7
+ data.tar.gz: 0c0c04c6f1d4d57114d50d603fabfbd3470da4f373f48b091991e228306080f47bd3643e5c5c706fe9e3992e661b656b4634c881ee0861b79fbfa1f63a60d8e5
data/CHANGELOG.md CHANGED
@@ -15,10 +15,21 @@ Changes since the last non-beta release.
15
15
  _Please add entries here for your pull requests that are not yet released._
16
16
 
17
17
  ## [1.1.2] - 2023-10-17
18
+
18
19
  ### Fixed
19
20
 
20
21
  - Fixed failed build on MacOS by adding platform flag and fixed multiple files in yaml document for template. [PR 81](https://github.com/shakacode/heroku-to-control-plane/pull/81) by [justin808](https://github.com/justin808).
21
22
 
23
+ ### Added
24
+
25
+ - Added `open-console` command to open the app console on Control Plane. [PR 83](https://github.com/shakacode/heroku-to-control-plane/pull/83) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
26
+ - Added option to set the org with a `CPLN_ORG` env var. [PR 83](https://github.com/shakacode/heroku-to-control-plane/pull/83) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
27
+ - Added `--verbose` option to all commands for more detailed logs. [PR 83](https://github.com/shakacode/heroku-to-control-plane/pull/83) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
28
+
29
+ ### Changed
30
+
31
+ - Calling `cpl` with no command now shows the help menu. [PR 83](https://github.com/shakacode/heroku-to-control-plane/pull/83) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
32
+
22
33
  ## [1.1.1] - 2023-09-23
23
34
 
24
35
  ### Fixed
@@ -84,7 +95,9 @@ _Please add entries here for your pull requests that are not yet released._
84
95
 
85
96
  - Initial release
86
97
 
87
- [Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.1.0...HEAD
98
+ [Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.1.2...HEAD
99
+ [1.1.2]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.1.1...v1.1.2
100
+ [1.1.1]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.1.0...v1.1.1
88
101
  [1.1.0]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.4...v1.1.0
89
102
  [1.0.4]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.3...v1.0.4
90
103
  [1.0.3]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.2...v1.0.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (1.1.2.rc.0)
4
+ cpl (1.1.2)
5
5
  debug (~> 1.7.1)
6
6
  dotenv (~> 2.8.1)
7
7
  psych (~> 5.1.0)
data/README.md CHANGED
@@ -29,17 +29,18 @@ a **helper CLI** based on templates to save lots of day-to-day typing (and human
29
29
  2. [Concept Mapping](#concept-mapping)
30
30
  3. [Installation](#installation)
31
31
  4. [Steps to Migrate](#steps-to-migrate)
32
- 5. [Config](#config)
33
- 6. [Environment](#environment)
34
- 7. [Database](#database)
35
- 8. [In-memory Databases](#in-memory-databases)
36
- 9. [Scheduled Jobs](#scheduled-jobs)
37
- 10. [CLI Commands Reference](#cli-commands-reference)
38
- 11. [Mapping of Heroku Commands to `cpl` and `cpln`](#mapping-of-heroku-commands-to-cpl-and-cpln)
39
- 12. [Examples](#examples)
40
- 13. [Migrating Postgres Database from Heroku Infrastructure](/docs/postgres.md)
41
- 14. [Migrating Redis Database from Heroku Infrastructure](/docs/redis.md)
42
- 15. [Tips](/docs/tips.md)
32
+ 5. [Configuration Files](#configuration-files)
33
+ 6. [Workflow](#workflow)
34
+ 7. [Environment](#environment)
35
+ 8. [Database](#database)
36
+ 9. [In-memory Databases](#in-memory-databases)
37
+ 10. [Scheduled Jobs](#scheduled-jobs)
38
+ 11. [CLI Commands Reference](#cli-commands-reference)
39
+ 12. [Mapping of Heroku Commands to `cpl` and `cpln`](#mapping-of-heroku-commands-to-cpl-and-cpln)
40
+ 13. [Examples](#examples)
41
+ 14. [Migrating Postgres Database from Heroku Infrastructure](/docs/postgres.md)
42
+ 15. [Migrating Redis Database from Heroku Infrastructure](/docs/redis.md)
43
+ 16. [Tips](/docs/tips.md)
43
44
 
44
45
  ## Key Features
45
46
 
@@ -89,23 +90,31 @@ For the typical Rails app, this means:
89
90
 
90
91
  ## Installation
91
92
 
92
- 1. Ensure your [Control Plane](https://controlplane.com) account is set up. Set up an `organization` <your-org> for testing in that account and modify value for `aliases.common.cpln_org` in `.controlplane/controlplane.yml`. If you need an organization, please [contact Shakcode](mailto:controlplane@shkacode.com).
93
- 1. Install [Node.js](https://nodejs.org/en) (required for Control Plane CLI).
93
+ 1. Ensure your [Control Plane](https://controlplane.com) account is set up. Set up an `organization` <your-org> for testing in that account and modify the value for `aliases.common.cpln_org` in `.controlplane/controlplane.yml`, or you can also set it with the `CPLN_ORG` environment variable. If you need an organization, please [contact Shakacode](mailto:controlplane@shakacode.com).
94
94
 
95
- 1. Install [Ruby](https://www.ruby-lang.org/en/) (required for these helpers).
95
+ 2. Install [Node.js](https://nodejs.org/en) (required for Control Plane CLI).
96
+
97
+ 3. Install [Ruby](https://www.ruby-lang.org/en/) (required for these helpers).
98
+
99
+ 4. Install Control Plane CLI, and configure access ([docs here](https://docs.controlplane.com/quickstart/quick-start-3-cli#getting-started-with-the-cli)).
96
100
 
97
- 1. Install Control Plane CLI (and configure access) [docs here](https://docs.controlplane.com/quickstart/quick-start-3-cli#getting-started-with-the-cli), `npm install -g @controlplane/cli`. You can update the `cpln` command line with `npm update -g @controlplane/cli`. Then run `cpln login` to ensure access.
98
101
  ```sh
102
+ # Install CLI
99
103
  npm install -g @controlplane/cli
104
+
105
+ # Configure access
100
106
  cpln login
107
+
108
+ # Update CLI
109
+ npm update -g @controlplane/cli
101
110
  ```
102
111
 
103
- 1. Run `cpln image docker-login --org <your-org>` to ensure that you have access to the Control Plane Docker registry.
112
+ 5. Run `cpln image docker-login --org <your-org>` to ensure that you have access to the Control Plane Docker registry.
104
113
 
105
- 1. Install Heroku to Control Plane `cpl` CLI, either as a [Ruby gem](https://rubygems.org/gems/cpl) or a local clone.
114
+ 6. Install Heroku to Control Plane `cpl` CLI, either as a [Ruby gem](https://rubygems.org/gems/cpl) or a local clone.
106
115
  For information on the latter, see [CONTRIBUTING.md](CONTRIBUTING.md). You may also install `cpl` in your project's Gemfile.
107
116
 
108
- 1. This project has a `Dockerfile` for Control Plane in this directory. You can use it as an example for your project. Ensure that you have Docker running.
117
+ 7. You can use [this Dockerfile](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/Dockerfile) as an example for your project. Ensure that you have Docker running.
109
118
 
110
119
  **Note:** Do not confuse the `cpl` CLI with the `cpln` CLI. The `cpl` CLI is the Heroku to Control Plane playbook CLI.
111
120
  The `cpln` CLI is the Control Plane CLI.
@@ -116,7 +125,7 @@ Click [here](/docs/migrating.md) to see the steps to migrate.
116
125
 
117
126
  ## Configuration Files
118
127
 
119
- The `cpl` gem is based on several configuration files within a `/.controlplane` top-level directory in your Rails project.
128
+ The `cpl` gem is based on several configuration files within a `/.controlplane` top-level directory in your project.
120
129
 
121
130
  ```
122
131
  .controlplane/
@@ -129,17 +138,18 @@ The `cpl` gem is based on several configuration files within a `/.controlplane`
129
138
  ├─ entrypoint.sh
130
139
  ```
131
140
 
132
- 1. `controlplane.yml` describes the overall application. Be sure to have <your-org> as the value for `aliases.common.cpln_org`.
141
+ 1. `controlplane.yml` describes the overall application. Be sure to have <your-org> as the value for `aliases.common.cpln_org`, or set it with the `CPLN_ORG` environment variable.
133
142
  2. `Dockerfile` builds the production application. `entrypoint.sh` is an _example_ entrypoint script for the production application, referenced in your Dockerfile.
134
143
  3. `templates` directory contains the templates for the various workloads, such as `rails.yml` and `postgres.yml`.
135
- 4. `templates/gvc.yml` defines your project's GVC (like a Heroku app). Most importantly, it contains ENV values for app.
136
- 5. `templates/rails.yml` defines your Rails workload. It may inherit ENV values from the parent GVC, which is populated from the `templates/gvc.yml`. This file also configures scaling, sizing, firewalls, and other workload specific values.
137
- 6. For other workloads (like lines in a Heroku Procfile), you create additional template files. For example, you can base a `templates/sidekiq.yml` on the `templates/rails.yml` file.
138
- 7. You can have other files in the `templates` directory, such as `redis.yml` and `postgres.yml` which could setup Redis and Postgres for a testing application.
144
+ 4. `templates/gvc.yml` defines your project's GVC (like a Heroku app). More importantly, it contains ENV values for the app.
145
+ 5. `templates/rails.yml` defines your Rails workload. It may inherit ENV values from the parent GVC, which is populated from the `templates/gvc.yml`. This file also configures scaling, sizing, firewalls, and other workload-specific values.
146
+ 6. For other workloads (like lines in a Heroku `Procfile`), you create additional template files. For example, you can base a `templates/sidekiq.yml` on the `templates/rails.yml` file.
147
+ 7. You can have other files in the `templates` directory, such as `redis.yml` and `postgres.yml`, which could setup Redis and Postgres for a testing application.
139
148
 
140
149
  Here's a complete example of all supported config keys explained for the `controlplane.yml` file:
141
-
150
+
142
151
  ### `controlplane.yml`
152
+
143
153
  ```yaml
144
154
  # Keys beginning with "cpln_" correspond to your settings in Control Plane.
145
155
 
@@ -234,58 +244,64 @@ apps:
234
244
 
235
245
  ## Workflow
236
246
 
237
- For a live example, see the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md).
247
+ For a live example, see the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md) repository.
248
+
238
249
  This example should closely match the below example.
239
250
 
240
251
  Suppose your app is called `tutorial-app`. You can run the following commands.
241
252
 
242
253
  ### Setup Commands
254
+
243
255
  ```sh
244
256
  # Provision all infrastructure on Control Plane.
245
- # app tutorial-app will be created per definition in .controlplane/controlplane.yml
257
+ # `tutorial-app` will be created per definition in .controlplane/controlplane.yml.
246
258
  cpl apply-template gvc postgres redis rails -a tutorial-app
247
259
 
248
- # Build and push docker image to Control Plane repository
249
- # Note, may take many minutes. Be patient. Check for error messages, such as forgetting to run `cpln image docker-login --org <your-org>`
260
+ # Build and push the Docker image to the Control Plane repository.
261
+ # Note, it may take many minutes. Be patient.
262
+ # Check for error messages, such as forgetting to run `cpln image docker-login --org <your-org>`.
250
263
  cpl build-image -a tutorial-app
251
264
 
252
- # Promote image to app after running `cpl build-image command`
253
- # Note, the UX of images may not show the image for up to 5 minutes. However, it's ready.
265
+ # Promote the image to the app after running the `cpl build-image` command.
266
+ # Note, the UX of the images may not show the image for up to 5 minutes. However, it's ready.
254
267
  cpl deploy-image -a tutorial-app
255
268
 
256
- # See how app is starting up
269
+ # See how the app is starting up.
257
270
  cpl logs -a tutorial-app
258
271
 
259
- # Open app in browser (once it has started up)
272
+ # Open the app in browser (once it has started up).
260
273
  cpl open -a tutorial-app
261
274
  ```
262
275
 
263
- ### Promoting code updates
276
+ ### Promoting Code Updates
264
277
 
265
278
  After committing code, you will update your deployment of `tutorial-app` with the following commands:
266
279
 
267
280
  ```sh
268
- # Build and push new image with sequential image tagging, e.g. 'tutorial-app:1', then 'tutorial-app:2', etc.
281
+ # Build and push a new image with sequential image tagging, e.g. 'tutorial-app:1', then 'tutorial-app:2', etc.
269
282
  cpl build-image -a tutorial-app
270
283
 
271
- # Run database migrations (or other release tasks) with latest image,
272
- # while app is still running on previous image.
284
+ # Run database migrations (or other release tasks) with the latest image,
285
+ # while the app is still running on the previous image.
273
286
  # This is analogous to the release phase.
274
- cpl runner rails db:migrate -a tutorial-app --image latest
287
+ cpl run:detached rails db:migrate -a tutorial-app --image latest
275
288
 
276
- # Pomote latest image to app
289
+ # Pomote the latest image to the app.
277
290
  cpl deploy-image -a tutorial-app
278
291
  ```
279
292
 
280
293
  If you needed to push a new image with a specific commit SHA, you can run the following command:
281
294
 
282
295
  ```sh
283
- # Build and push with sequential image tagging and commit SHA, e.g. 'tutorial-app:123_ABCD'
296
+ # Build and push with sequential image tagging and commit SHA, e.g. 'tutorial-app:123_ABCD', etc.
284
297
  cpl build-image -a tutorial-app --commit ABCD
285
298
  ```
286
299
 
287
300
  ### Real World
288
- Most companies will configure their CI system to handle the above steps. Please [contact Shakcode](mailto:controlplane@shkacode.com) for examples of how to do this, jump on [**React+Rails Slack channel**] (https://reactrails.slack.com/join/shared_invite/enQtNjY3NTczMjczNzYxLTlmYjdiZmY3MTVlMzU2YWE0OWM0MzNiZDI0MzdkZGFiZTFkYTFkOGVjODBmOWEyYWQ3MzA2NGE1YWJjNmVlMGE).
301
+
302
+ Most companies will configure their CI system to handle the above steps. Please [contact Shakacode](mailto:controlplane@shakacode.com) for examples of how to do this.
303
+
304
+ You can also join our [**Slack channel**](https://reactrails.slack.com/join/shared_invite/enQtNjY3NTczMjczNzYxLTlmYjdiZmY3MTVlMzU2YWE0OWM0MzNiZDI0MzdkZGFiZTFkYTFkOGVjODBmOWEyYWQ3MzA2NGE1YWJjNmVlMGE) for ShakaCode open source projects.
289
305
 
290
306
  ## Environment
291
307
 
@@ -307,25 +323,27 @@ It is also possible to set up a Secret store (of type `Dictionary`), which we ca
307
323
  Policy to access the secret.
308
324
 
309
325
  In `templates/gvc.yml`:
326
+
310
327
  ```yaml
311
328
  spec:
312
329
  env:
313
330
  - name: MY_GLOBAL_VAR
314
- value: 'value'
331
+ value: "value"
315
332
  - name: MY_SECRET_GLOBAL_VAR
316
- value: 'cpln://secret/MY_SECRET_STORE_NAME/MY_SECRET_GLOBAL_VAR'
333
+ value: "cpln://secret/MY_SECRET_STORE_NAME/MY_SECRET_GLOBAL_VAR"
317
334
  ```
318
335
 
319
336
  In `templates/rails.yml`:
337
+
320
338
  ```yaml
321
339
  spec:
322
340
  containers:
323
341
  - name: rails
324
342
  env:
325
343
  - name: MY_LOCAL_VAR
326
- value: 'value'
344
+ value: "value"
327
345
  - name: MY_SECRET_LOCAL_VAR
328
- value: 'cpln://secret/MY_SECRET_STORE_NAME/MY_SECRET_LOCAL_VAR'
346
+ value: "cpln://secret/MY_SECRET_STORE_NAME/MY_SECRET_LOCAL_VAR"
329
347
  inheritEnv: true # To enable global env inheritance.
330
348
  ```
331
349
 
data/docs/commands.md CHANGED
@@ -227,6 +227,15 @@ cpl open -a $APP_NAME
227
227
  cpl open -a $APP_NAME -w $WORKLOAD_NAME
228
228
  ```
229
229
 
230
+ ### `open-console`
231
+
232
+ - Opens the app console on Control Plane in the default browser
233
+ - Can also go directly to a workload page if `--workload` is provided
234
+
235
+ ```sh
236
+ cpl open-console -a $APP_NAME
237
+ ```
238
+
230
239
  ### `promote-app-from-upstream`
231
240
 
232
241
  - Copies the latest image from upstream, runs a release script (optional), and deploys the image
@@ -35,13 +35,12 @@ module Command
35
35
  ```
36
36
  EX
37
37
 
38
- def call # rubocop:disable Metrics/MethodLength
38
+ def call # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity
39
39
  ensure_templates!
40
40
 
41
- @app_status = :existing
42
- @created_workloads = []
43
- @failed_workloads = []
44
- @skipped_workloads = []
41
+ @created_items = []
42
+ @failed_templates = []
43
+ @skipped_templates = []
45
44
 
46
45
  @asked_for_confirmation = false
47
46
 
@@ -57,9 +56,11 @@ module Command
57
56
 
58
57
  pending_templates.each do |template, filename|
59
58
  step("Applying template '#{template}'", abort_on_error: false) do
60
- apply_template(filename)
61
- if $CHILD_STATUS.success?
62
- report_success(template)
59
+ items = apply_template(filename)
60
+ if items
61
+ items.each do |item|
62
+ report_success(item)
63
+ end
63
64
  else
64
65
  report_failure(template)
65
66
  end
@@ -68,10 +69,9 @@ module Command
68
69
  end
69
70
  end
70
71
 
71
- print_app_status
72
- print_created_workloads
73
- print_failed_workloads
74
- print_skipped_workloads
72
+ print_created_items
73
+ print_failed_templates
74
+ print_skipped_templates
75
75
  end
76
76
 
77
77
  private
@@ -134,62 +134,37 @@ module Command
134
134
  cp.apply_template(data)
135
135
  end
136
136
 
137
- def report_success(template)
138
- if template == "gvc"
139
- @app_status = :success
140
- else
141
- @created_workloads.push(template)
142
- end
137
+ def report_success(item)
138
+ @created_items.push(item)
143
139
  end
144
140
 
145
141
  def report_failure(template)
146
- if template == "gvc"
147
- @app_status = :failure
148
- else
149
- @failed_workloads.push(template)
150
- end
142
+ @failed_templates.push(template)
151
143
  end
152
144
 
153
145
  def report_skipped(template)
154
- if template == "gvc"
155
- @app_status = :skipped
156
- else
157
- @skipped_workloads.push(template)
158
- end
159
- end
160
-
161
- def print_app_status
162
- return if @app_status == :existing
163
-
164
- case @app_status
165
- when :success
166
- progress.puts("\n#{Shell.color("Created app '#{config.app}'.", :green)}")
167
- when :failure
168
- progress.puts("\n#{Shell.color("Failed to create app '#{config.app}'.", :red)}")
169
- when :skipped
170
- progress.puts("\n#{Shell.color("Skipped app '#{config.app}' (already exists).", :blue)}")
171
- end
146
+ @skipped_templates.push(template)
172
147
  end
173
148
 
174
- def print_created_workloads
175
- return unless @created_workloads.any?
149
+ def print_created_items
150
+ return unless @created_items.any?
176
151
 
177
- workloads = @created_workloads.map { |template| " - #{template}" }.join("\n")
178
- progress.puts("\n#{Shell.color('Created workloads:', :green)}\n#{workloads}")
152
+ created = @created_items.map { |item| " - [#{item[:kind]}] #{item[:name]}" }.join("\n")
153
+ progress.puts("\n#{Shell.color('Created items:', :green)}\n#{created}")
179
154
  end
180
155
 
181
- def print_failed_workloads
182
- return unless @failed_workloads.any?
156
+ def print_failed_templates
157
+ return unless @failed_templates.any?
183
158
 
184
- workloads = @failed_workloads.map { |template| " - #{template}" }.join("\n")
185
- progress.puts("\n#{Shell.color('Failed to create workloads:', :red)}\n#{workloads}")
159
+ failed = @failed_templates.map { |template| " - #{template}" }.join("\n")
160
+ progress.puts("\n#{Shell.color('Failed to apply templates:', :red)}\n#{failed}")
186
161
  end
187
162
 
188
- def print_skipped_workloads
189
- return unless @skipped_workloads.any?
163
+ def print_skipped_templates
164
+ return unless @skipped_templates.any?
190
165
 
191
- workloads = @skipped_workloads.map { |template| " - #{template}" }.join("\n")
192
- progress.puts("\n#{Shell.color('Skipped workloads (already exist):', :blue)}\n#{workloads}")
166
+ skipped = @skipped_templates.map { |template| " - #{template}" }.join("\n")
167
+ progress.puts("\n#{Shell.color('Skipped templates (already exist):', :blue)}\n#{skipped}")
193
168
  end
194
169
  end
195
170
  end
data/lib/command/base.rb CHANGED
@@ -176,6 +176,18 @@ module Command
176
176
  }
177
177
  end
178
178
 
179
+ def self.verbose_option(required: false)
180
+ {
181
+ name: :verbose,
182
+ params: {
183
+ aliases: ["-d"],
184
+ desc: "Shows detailed logs",
185
+ type: :boolean,
186
+ required: required
187
+ }
188
+ }
189
+ end
190
+
179
191
  def self.all_options
180
192
  methods.grep(/_option$/).map { |method| send(method.to_s) }
181
193
  end
@@ -21,6 +21,11 @@ module Command
21
21
  EX
22
22
 
23
23
  def call # rubocop:disable Metrics/MethodLength
24
+ if config.org_comes_from_env
25
+ puts Shell.color("Org comes from CPLN_ORG env var", :yellow)
26
+ puts
27
+ end
28
+
24
29
  if config.app
25
30
  puts "#{Shell.color("Current config (app '#{config.app}')", :blue)}:"
26
31
  puts pretty_print(config.current)
@@ -29,7 +29,7 @@ module Command
29
29
  ensure_docker_running!
30
30
 
31
31
  @upstream = config[:upstream]
32
- @upstream_org = config.apps[@upstream.to_sym][:cpln_org]
32
+ @upstream_org = config.apps[@upstream.to_sym][:cpln_org] || ENV.fetch("CPLN_ORG_UPSTREAM", nil)
33
33
  ensure_upstream_org!
34
34
 
35
35
  create_upstream_profile
@@ -51,7 +51,10 @@ module Command
51
51
  end
52
52
 
53
53
  def ensure_upstream_org!
54
- raise "Can't find option 'cpln_org' for app '#{@upstream}' in 'controlplane.yml'." unless @upstream_org
54
+ return if @upstream_org
55
+
56
+ raise "Can't find option 'cpln_org' for app '#{@upstream}' in 'controlplane.yml', " \
57
+ "and CPLN_ORG_UPSTREAM env var is not set."
55
58
  end
56
59
 
57
60
  def create_upstream_profile
data/lib/command/info.rb CHANGED
@@ -81,17 +81,20 @@ module Command
81
81
  end
82
82
  end
83
83
 
84
- def orgs # rubocop:disable Metrics/MethodLength
84
+ def orgs # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
85
85
  result = []
86
86
 
87
87
  if config.options[:org]
88
88
  result.push(config.options[:org])
89
89
  else
90
+ org_from_env = ENV.fetch("CPLN_ORG", nil)
91
+ result.push(org_from_env) if org_from_env
92
+
90
93
  config.apps.each do |app_name, app_options|
91
94
  next if config.app && !app_matches?(config.app, app_name, app_options)
92
95
 
93
96
  org = app_options[:cpln_org]
94
- result.push(org) unless result.include?(org)
97
+ result.push(org) if org && !result.include?(org)
95
98
  end
96
99
  end
97
100
 
@@ -11,9 +11,11 @@ module Command
11
11
  HIDE = true
12
12
 
13
13
  def call
14
- return unless config.options[:version]
15
-
16
- Cpl::Cli.start(["version"])
14
+ if config.options[:version]
15
+ Cpl::Cli.start(["version"])
16
+ else
17
+ Cpl::Cli.start(["help"])
18
+ end
17
19
  end
18
20
  end
19
21
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Command
4
+ class OpenConsole < Base
5
+ NAME = "open-console"
6
+ OPTIONS = [
7
+ app_option(required: true),
8
+ workload_option
9
+ ].freeze
10
+ DESCRIPTION = "Opens the app console on Control Plane in the default browser"
11
+ LONG_DESCRIPTION = <<~DESC
12
+ - Opens the app console on Control Plane in the default browser
13
+ - Can also go directly to a workload page if `--workload` is provided
14
+ DESC
15
+
16
+ def call
17
+ workload = config.options[:workload]
18
+ url = "https://console.cpln.io/console/org/#{config.org}/gvc/#{config.app}"
19
+ url += "/workload/#{workload}" if workload
20
+ url += "/-info"
21
+ opener = `which xdg-open open`.split("\n").grep_v("not found").first
22
+
23
+ exec %(#{opener} "#{url}")
24
+ end
25
+ end
26
+ end
data/lib/core/config.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Config
3
+ class Config # rubocop:disable Metrics/ClassLength
4
4
  attr_reader :config, :current,
5
- :org, :app, :apps, :app_dir,
5
+ :org, :org_comes_from_env, :app, :apps, :app_dir,
6
6
  # command line options
7
7
  :args, :options
8
8
 
@@ -12,10 +12,13 @@ class Config
12
12
  @args = args
13
13
  @options = options
14
14
  @org = options[:org]
15
+ @org_comes_from_env = false
15
16
  @app = options[:app]
16
17
 
17
18
  load_app_config
18
19
  load_apps
20
+
21
+ Shell.verbose_mode(options[:verbose])
19
22
  end
20
23
 
21
24
  def [](key)
@@ -48,6 +51,13 @@ class Config
48
51
  raise "Can't find app '#{app_name}' in 'controlplane.yml'." unless current
49
52
  end
50
53
 
54
+ def ensure_current_config_org!(app_name)
55
+ return if @org
56
+
57
+ raise "Can't find option 'cpln_org' for app '#{app_name}' in 'controlplane.yml', " \
58
+ "and CPLN_ORG env var is not set."
59
+ end
60
+
51
61
  def ensure_config!
52
62
  raise "'controlplane.yml' is empty." unless config
53
63
  end
@@ -66,8 +76,15 @@ class Config
66
76
 
67
77
  def pick_current_config(app_name, app_options)
68
78
  @current = app_options
69
- @org = self[:cpln_org]
70
79
  ensure_current_config_app!(app_name)
80
+
81
+ if current.key?(:cpln_org)
82
+ @org = current.fetch(:cpln_org)
83
+ else
84
+ @org = ENV.fetch("CPLN_ORG", nil)
85
+ @org_comes_from_env = true
86
+ end
87
+ ensure_current_config_org!(app_name)
71
88
  end
72
89
 
73
90
  def load_apps # rubocop:disable Metrics/MethodLength
@@ -24,13 +24,13 @@ class Controlplane # rubocop:disable Metrics/ClassLength
24
24
 
25
25
  def profile_create(profile, token)
26
26
  cmd = "cpln profile create #{profile} --token #{token}"
27
- cmd += " > /dev/null" if Shell.tmp_stderr
27
+ cmd += " > /dev/null" if Shell.should_hide_output?
28
28
  perform!(cmd)
29
29
  end
30
30
 
31
31
  def profile_delete(profile)
32
32
  cmd = "cpln profile delete #{profile}"
33
- cmd += " > /dev/null" if Shell.tmp_stderr
33
+ cmd += " > /dev/null" if Shell.should_hide_output?
34
34
  perform!(cmd)
35
35
  end
36
36
 
@@ -61,25 +61,25 @@ class Controlplane # rubocop:disable Metrics/ClassLength
61
61
 
62
62
  def image_login(org_name = config.org)
63
63
  cmd = "cpln image docker-login --org #{org_name}"
64
- cmd += " > /dev/null 2>&1" if Shell.tmp_stderr
64
+ cmd += " > /dev/null 2>&1" if Shell.should_hide_output?
65
65
  perform!(cmd)
66
66
  end
67
67
 
68
68
  def image_pull(image)
69
69
  cmd = "docker pull #{image}"
70
- cmd += " > /dev/null" if Shell.tmp_stderr
70
+ cmd += " > /dev/null" if Shell.should_hide_output?
71
71
  perform!(cmd)
72
72
  end
73
73
 
74
74
  def image_tag(old_tag, new_tag)
75
75
  cmd = "docker tag #{old_tag} #{new_tag}"
76
- cmd += " > /dev/null" if Shell.tmp_stderr
76
+ cmd += " > /dev/null" if Shell.should_hide_output?
77
77
  perform!(cmd)
78
78
  end
79
79
 
80
80
  def image_push(image)
81
81
  cmd = "docker push #{image}"
82
- cmd += " > /dev/null" if Shell.tmp_stderr
82
+ cmd += " > /dev/null" if Shell.should_hide_output?
83
83
  perform!(cmd)
84
84
  end
85
85
 
@@ -148,7 +148,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
148
148
  end
149
149
 
150
150
  def workload_get_replicas_safely(workload, location:)
151
- cmd = "cpln workload get-replicas #{workload} #{gvc_org} --location #{location} -o yaml 2> /dev/null"
151
+ cmd = "cpln workload get-replicas #{workload} #{gvc_org} --location #{location} -o yaml"
152
+ cmd += " 2> /dev/null" if Shell.should_hide_output?
153
+
154
+ Shell.debug("CMD", cmd)
155
+
152
156
  result = `#{cmd}`
153
157
  $CHILD_STATUS.success? ? YAML.safe_load(result) : nil
154
158
  end
@@ -180,7 +184,7 @@ class Controlplane # rubocop:disable Metrics/ClassLength
180
184
  def workload_set_image_ref(workload, container:, image:)
181
185
  cmd = "cpln workload update #{workload} #{gvc_org}"
182
186
  cmd += " --set spec.containers.#{container}.image=/org/#{config.org}/image/#{image}"
183
- cmd += " > /dev/null" if Shell.tmp_stderr
187
+ cmd += " > /dev/null" if Shell.should_hide_output?
184
188
  perform!(cmd)
185
189
  end
186
190
 
@@ -208,7 +212,7 @@ class Controlplane # rubocop:disable Metrics/ClassLength
208
212
 
209
213
  def workload_force_redeployment(workload)
210
214
  cmd = "cpln workload force-redeployment #{workload} #{gvc_org}"
211
- cmd += " > /dev/null" if Shell.tmp_stderr
215
+ cmd += " > /dev/null" if Shell.should_hide_output?
212
216
  perform!(cmd)
213
217
  end
214
218
 
@@ -280,41 +284,77 @@ class Controlplane # rubocop:disable Metrics/ClassLength
280
284
  Tempfile.create do |f|
281
285
  f.write(data)
282
286
  f.rewind
283
- cmd = "cpln apply #{gvc_org} --file #{f.path} > /dev/null"
287
+ cmd = "cpln apply #{gvc_org} --file #{f.path}"
284
288
  if Shell.tmp_stderr
285
- cmd += " 2> #{Shell.tmp_stderr.path}"
286
- perform(cmd)
289
+ cmd += " 2> #{Shell.tmp_stderr.path}" if Shell.should_hide_output?
290
+
291
+ Shell.debug("CMD", cmd)
292
+
293
+ result = `#{cmd}`
294
+ $CHILD_STATUS.success? ? parse_apply_result(result) : false
287
295
  else
288
- perform!(cmd)
296
+ Shell.debug("CMD", cmd)
297
+
298
+ result = `#{cmd}`
299
+ $CHILD_STATUS.success? ? parse_apply_result(result) : exit(false)
289
300
  end
290
301
  end
291
302
  end
292
303
 
293
- def apply_hash(data) # rubocop:disable Metrics/MethodLength
294
- Tempfile.create do |f|
295
- f.write(data.to_yaml)
296
- f.rewind
297
- cmd = "cpln apply #{gvc_org} --file #{f.path} > /dev/null"
298
- if Shell.tmp_stderr
299
- cmd += " 2> #{Shell.tmp_stderr.path}"
300
- perform(cmd)
304
+ def apply_hash(data)
305
+ apply_template(data.to_yaml)
306
+ end
307
+
308
+ def parse_apply_result(result) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
309
+ items = []
310
+
311
+ lines = result.split("\n")
312
+ lines.each do |line|
313
+ # The line can be in one of these formats:
314
+ # - "Created /org/shakacode-open-source-examples/gvc/my-app-staging"
315
+ # - "Created /org/shakacode-open-source-examples/gvc/my-app-staging/workload/redis"
316
+ # - "Updated gvc 'tutorial-app-test-1'"
317
+ # - "Updated workload 'redis'"
318
+ if line.start_with?("Created")
319
+ matches = line.match(%r{Created\s/org/[^/]+/gvc/([^/]+)($|(/([^/]+)/([^/]+)$))})&.captures
320
+ next unless matches
321
+
322
+ app, _, __, kind, name = matches
323
+ if kind
324
+ items.push({ kind: kind, name: name })
325
+ else
326
+ items.push({ kind: "app", name: app })
327
+ end
301
328
  else
302
- perform!(cmd)
329
+ matches = line.match(/Updated\s([^\s]+)\s'([^\s]+)'$/)&.captures
330
+ next unless matches
331
+
332
+ kind, name = matches
333
+ kind = "app" if kind == "gvc"
334
+ items.push({ kind: kind, name: name })
303
335
  end
304
336
  end
337
+
338
+ items
305
339
  end
306
340
 
307
341
  private
308
342
 
309
343
  def perform(cmd)
344
+ Shell.debug("CMD", cmd)
345
+
310
346
  system(cmd)
311
347
  end
312
348
 
313
349
  def perform!(cmd)
350
+ Shell.debug("CMD", cmd)
351
+
314
352
  system(cmd) || exit(false)
315
353
  end
316
354
 
317
355
  def perform_yaml(cmd)
356
+ Shell.debug("CMD", cmd)
357
+
318
358
  result = `#{cmd}`
319
359
  $CHILD_STATUS.success? ? YAML.safe_load(result) : exit(false)
320
360
  end
@@ -24,6 +24,8 @@ class ControlplaneApiDirect
24
24
  request["Authorization"] = api_token
25
25
  request.body = body.to_json if body
26
26
 
27
+ Shell.debug(method.upcase, "#{uri} #{body&.to_json}")
28
+
27
29
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
28
30
 
29
31
  case response
data/lib/core/shell.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Shell
4
4
  class << self
5
- attr_reader :tmp_stderr
5
+ attr_reader :tmp_stderr, :verbose
6
6
  end
7
7
 
8
8
  def self.shell
@@ -50,4 +50,16 @@ class Shell
50
50
  def self.abort(message)
51
51
  Kernel.abort(color("ERROR: #{message}", :red))
52
52
  end
53
+
54
+ def self.verbose_mode(verbose)
55
+ @verbose = verbose
56
+ end
57
+
58
+ def self.debug(prefix, message)
59
+ stderr.puts("\n[#{color(prefix, :red)}] #{message}") if verbose
60
+ end
61
+
62
+ def self.should_hide_output?
63
+ tmp_stderr && !verbose
64
+ end
53
65
  end
data/lib/cpl/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "1.1.2.rc.0"
4
+ VERSION = "1.1.2"
5
5
  MIN_CPLN_VERSION = "0.0.71"
6
6
  end
data/lib/cpl.rb CHANGED
@@ -141,7 +141,7 @@ module Cpl
141
141
  usage = command_class::USAGE.empty? ? name : command_class::USAGE
142
142
  requires_args = command_class::REQUIRES_ARGS
143
143
  default_args = command_class::DEFAULT_ARGS
144
- command_options = command_class::OPTIONS
144
+ command_options = command_class::OPTIONS + [::Command::Base.verbose_option]
145
145
  description = command_class::DESCRIPTION
146
146
  long_description = command_class::LONG_DESCRIPTION
147
147
  examples = command_class::EXAMPLES
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2.rc.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-10-18 00:00:00.000000000 Z
12
+ date: 2023-10-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug
@@ -251,6 +251,7 @@ files:
251
251
  - lib/command/maintenance_set_page.rb
252
252
  - lib/command/no_command.rb
253
253
  - lib/command/open.rb
254
+ - lib/command/open_console.rb
254
255
  - lib/command/promote_app_from_upstream.rb
255
256
  - lib/command/ps.rb
256
257
  - lib/command/ps_restart.rb
@@ -303,9 +304,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
303
304
  version: 2.7.0
304
305
  required_rubygems_version: !ruby/object:Gem::Requirement
305
306
  requirements:
306
- - - ">"
307
+ - - ">="
307
308
  - !ruby/object:Gem::Version
308
- version: 1.3.1
309
+ version: '0'
309
310
  requirements: []
310
311
  rubygems_version: 3.4.12
311
312
  signing_key: