cpl 1.1.2.rc.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: