cpl 0.5.1 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5989a3c887eb311dcfb8bffe88e8519172b21efd21e715c363e7a166b73dbc3
4
- data.tar.gz: b9fc9896cdd99a38b89389866f0f0825cb3944099e4579f4641ee221f2302a92
3
+ metadata.gz: 976c390927b51f67afe7a161b7185242261afb4c24db893026457b205fe61b12
4
+ data.tar.gz: b55bec82c485eb413c9a8787d34172e2c7e89212c15e319f3f626c652c3ac6e7
5
5
  SHA512:
6
- metadata.gz: c73027a84228c2371999bdff122d3bab5a3970d5f11c54f55a4b47a0fae77f83903e8d5702ecdd6baa5ac9fe6346f8e433f395a6fc3e22ee3a7225ed661038c3
7
- data.tar.gz: a2734ae8f9969be0d523dd547783284774ad461fa1dee36174a5c6bc6b653ec7a020c2c07301e31c787d5d4f7b04c4a6d983fe1e544d2d20410a54f19896d7ff
6
+ metadata.gz: 678825b452c56d5c481639de70904ab087f29e362c4b8ced34d3c2131f15a176f78c0c928b02449ebc96a0e69bd1e5c2cd1982577e06a0b62000aa0993bd4f91
7
+ data.tar.gz: a40e2ea6bfb43122c919d9126d6fffdb6a9722396bed1c4b22b5874d06f9b2126ee4f14e6df37047bb417bcb0788b3b19869d03b34801030b6e8e373f47950c2
data/.rubocop.yml CHANGED
@@ -14,3 +14,9 @@ Style/Documentation:
14
14
 
15
15
  Style/StringLiterals:
16
16
  EnforcedStyle: double_quotes
17
+
18
+ RSpec/ExampleLength:
19
+ Enabled: false
20
+
21
+ RSpec/MultipleExpectations:
22
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (0.5.1)
4
+ cpl (0.7.0)
5
5
  debug (~> 1.7.1)
6
6
  dotenv (~> 2.8.1)
7
7
  psych (~> 5.1.0)
@@ -10,17 +10,22 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
+ addressable (2.8.4)
14
+ public_suffix (>= 2.0.2, < 6.0)
13
15
  ast (2.4.2)
14
16
  childprocess (4.1.0)
17
+ crack (0.4.5)
18
+ rexml
15
19
  debug (1.7.2)
16
20
  irb (>= 1.5.0)
17
21
  reline (>= 0.3.1)
18
22
  diff-lcs (1.5.0)
19
23
  docile (1.4.0)
20
24
  dotenv (2.8.1)
25
+ hashdiff (1.0.1)
21
26
  iniparse (1.5.0)
22
27
  io-console (0.6.0)
23
- irb (1.6.3)
28
+ irb (1.6.4)
24
29
  reline (>= 0.3.0)
25
30
  json (2.6.3)
26
31
  overcommit (0.60.0)
@@ -32,6 +37,7 @@ GEM
32
37
  ast (~> 2.4.1)
33
38
  psych (5.1.0)
34
39
  stringio
40
+ public_suffix (5.0.1)
35
41
  rainbow (3.1.1)
36
42
  rake (13.0.6)
37
43
  regexp_parser (2.6.2)
@@ -77,9 +83,15 @@ GEM
77
83
  simplecov_json_formatter (~> 0.1)
78
84
  simplecov-html (0.12.3)
79
85
  simplecov_json_formatter (0.1.4)
80
- stringio (3.0.5)
81
- thor (1.2.1)
86
+ stringio (3.0.6)
87
+ thor (1.2.2)
88
+ timecop (0.9.6)
82
89
  unicode-display_width (2.4.2)
90
+ vcr (6.1.0)
91
+ webmock (3.18.1)
92
+ addressable (>= 2.8.0)
93
+ crack (>= 0.3.2)
94
+ hashdiff (>= 0.4.0, < 2.0.0)
83
95
 
84
96
  PLATFORMS
85
97
  ruby
@@ -94,6 +106,9 @@ DEPENDENCIES
94
106
  rubocop-rake (~> 0.6.0)
95
107
  rubocop-rspec (~> 2.18.1)
96
108
  simplecov (~> 0.22.0)
109
+ timecop (~> 0.9.6)
110
+ vcr (~> 6.1.0)
111
+ webmock (~> 3.18.1)
97
112
 
98
113
  BUNDLED WITH
99
114
  2.3.26
data/README.md CHANGED
@@ -28,11 +28,12 @@ To simplify migration to and usage of Control Plane for Heroku users, this repos
28
28
  6. [Environment](#environment)
29
29
  7. [Database](#database)
30
30
  8. [In-memory databases](#in-memory-databases)
31
- 9. [CLI commands reference](#cli-commands-reference)
32
- 10. [Mapping of Heroku Commands to `cpl` and `cpln`](#mapping-of-heroku-commands-to-cpl-and-cpln)
33
- 11. [Examples](#examples)
34
- 12. [Migrating Postgres database from Heroku infrastructure](/docs/postgres.md)
35
- 13. [Migrating Redis database from Heroku infrastructure](/docs/redis.md)
31
+ 9. [Scheduled jobs](#scheduled-jobs)
32
+ 10. [CLI commands reference](#cli-commands-reference)
33
+ 11. [Mapping of Heroku Commands to `cpl` and `cpln`](#mapping-of-heroku-commands-to-cpl-and-cpln)
34
+ 12. [Examples](#examples)
35
+ 13. [Migrating Postgres database from Heroku infrastructure](/docs/postgres.md)
36
+ 14. [Migrating Redis database from Heroku infrastructure](/docs/redis.md)
36
37
 
37
38
  ## Key features
38
39
 
@@ -105,14 +106,28 @@ Do not confuse the `cpl` CLI with the `cpln` CLI. The `cpl` CLI is the Heroku to
105
106
  **Notes:**
106
107
 
107
108
  1. `myapp` is an app name defined in the `.controlplane/controlplane.yml` file, such as `ror-tutorial` in [this `controlplane.yml` file](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
108
- 2. Other files in the `.controlplane/templates` directory are used by the `cpl setup` command.
109
+ 2. Other files in the `.controlplane/templates` directory are used by the `cpl setup-app` and `cpl apply-template` commands.
109
110
 
110
111
  ### Initial Setup and Deployment
111
112
 
113
+ Before the initial setup, add the templates for the app to `.controlplane/controlplane.yml`, using the `setup` key:
114
+
115
+ ```yaml
116
+ myapp:
117
+ setup:
118
+ - gvc
119
+ - postgres
120
+ - redis
121
+ - memcached
122
+ - rails
123
+ - sidekiq
124
+ ```
125
+
126
+ Note how the templates correspond to files in the `.controlplane/templates` directory.
127
+
112
128
  ```sh
113
129
  # Provision infrastructure (one-time-only for new apps) using templates.
114
- # Note how the arguments correspond to files in the `.controlplane/templates` directory.
115
- cpl setup gvc postgres redis memcached rails sidekiq -a myapp
130
+ cpl setup-app -a myapp
116
131
 
117
132
  # Build and push image with auto-tagging "myapp:1_456".
118
133
  cpl build-image -a myapp --commit 456
@@ -214,7 +229,7 @@ apps:
214
229
  <<: *common
215
230
  # Use a different organization for production.
216
231
  cpln_org: my-org-production
217
- # Allows running the command `cpl pipeline-promote my-app-staging` to promote the staging app to production.
232
+ # Allows running the command `cpl promote-app-from-upstream -a my-app-production` to promote the staging app to production.
218
233
  upstream: my-app-staging
219
234
  my-app-other:
220
235
  <<: *common
@@ -313,6 +328,38 @@ For production purposes or where restarts are not an option, you should use exte
313
328
  We provide default `redis` and `memcached` templates in this repo optimized for Control Plane and suitable
314
329
  for development purposes.
315
330
 
331
+ ## Scheduled jobs
332
+
333
+ Control Plane supports scheduled jobs via [cron workloads](https://docs.controlplane.com/reference/workload#cron).
334
+
335
+ Here's a partial example of a template for a cron workload, using the app image:
336
+
337
+ ```yaml
338
+ kind: workload
339
+ name: daily-task
340
+ spec:
341
+ type: cron
342
+ job:
343
+ # Run daily job at 2am
344
+ schedule: 0 2 * * *
345
+ # Never or OnFailure
346
+ restartPolicy: Never
347
+ containers:
348
+ - name: daily-task
349
+ args:
350
+ - bundle
351
+ - exec
352
+ - rails
353
+ - db:prepare
354
+ image: "/org/APP_ORG/image/APP_IMAGE"
355
+ ```
356
+
357
+ A complete example can be found at [templates/daily-task.yml](templates/daily-task.yml), optimized for Control Plane and suitable for development purposes.
358
+
359
+ You can create the cron workload by adding the template for it to the `.controlplane/templates` folder and running `cpl apply-template my-template -a my-app`, where `my-template` is the name of the template file (`my-template.yml`).
360
+
361
+ Then to view the logs of the cron workload, you can run `cpl logs -a my-app -w my-template`.
362
+
316
363
  ## CLI commands reference:
317
364
 
318
365
  Click [here](/docs/commands.md) to see the commands.
@@ -327,17 +374,17 @@ cpl --help
327
374
 
328
375
  **`[WIP]`**
329
376
 
330
- | Heroku Command | `cpl` or `cpln` |
331
- | -------------------------------------------------------------------------------------------------------------- | --------------- |
332
- | [heroku ps](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-ps-type-type) | `cpl ps` |
333
- | [heroku config](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-config) | ? |
334
- | [heroku maintenance](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-maintenance) | ? |
335
- | [heroku logs](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-logs) | `cpl logs` |
336
- | [heroku pg](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pg-database) | ? |
337
- | [heroku pipelines:promote](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pipelines-promote) | `cpl promote` |
338
- | [heroku psql](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-psql-database) | ? |
339
- | [heroku redis](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-redis-database) | ? |
340
- | [heroku releases](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-releases) | ? |
377
+ | Heroku Command | `cpl` or `cpln` |
378
+ | -------------------------------------------------------------------------------------------------------------- | ------------------------------- |
379
+ | [heroku ps](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-ps-type-type) | `cpl ps` |
380
+ | [heroku config](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-config) | ? |
381
+ | [heroku maintenance](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-maintenance) | `cpl maintenance` |
382
+ | [heroku logs](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-logs) | `cpl logs` |
383
+ | [heroku pg](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pg-database) | ? |
384
+ | [heroku pipelines:promote](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pipelines-promote) | `cpl promote-app-from-upstream` |
385
+ | [heroku psql](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-psql-database) | ? |
386
+ | [heroku redis](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-redis-database) | ? |
387
+ | [heroku releases](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-releases) | ? |
341
388
 
342
389
  ## Examples
343
390
 
data/Rakefile CHANGED
@@ -4,11 +4,11 @@ require "bundler/gem_tasks"
4
4
  require "rspec/core/rake_task"
5
5
  require "rubocop/rake_task"
6
6
 
7
- RSpec::Core::RakeTask.new(:spec)
7
+ RSpec::Core::RakeTask.new(:rspec)
8
8
 
9
9
  RuboCop::RakeTask.new
10
10
 
11
- task default: %i[spec rubocop]
11
+ task default: %i[rspec rubocop]
12
12
 
13
13
  desc "Updates commands.md file"
14
14
  task :command_docs do
data/cpl.gemspec CHANGED
@@ -26,6 +26,9 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency "rubocop-rake", "~> 0.6.0"
27
27
  spec.add_development_dependency "rubocop-rspec", "~> 2.18.1"
28
28
  spec.add_development_dependency "simplecov", "~> 0.22.0"
29
+ spec.add_development_dependency "timecop", "~> 0.9.6"
30
+ spec.add_development_dependency "vcr", "~> 6.1.0"
31
+ spec.add_development_dependency "webmock", "~> 3.18.1"
29
32
 
30
33
  spec.files = `git ls-files -z`.split("\x0").reject do |file|
31
34
  file.match(%r{^(coverage|pkg|spec|tmp)/})
data/docs/commands.md CHANGED
@@ -11,11 +11,36 @@ This `-a` option is used in most of the commands and will pick all other app con
11
11
 
12
12
  ### Commands
13
13
 
14
+ ### `apply-template`
15
+
16
+ - Applies application-specific configs from templates (e.g., for every review-app)
17
+ - Publishes (creates or updates) those at Control Plane infrastructure
18
+ - Picks templates from the `.controlplane/templates` directory
19
+ - Templates are ordinary Control Plane templates but with variable preprocessing
20
+
21
+ **Preprocessed template variables:**
22
+
23
+ ```
24
+ APP_GVC - basically GVC or app name
25
+ APP_LOCATION - default location
26
+ APP_ORG - organization
27
+ APP_IMAGE - will use latest app image
28
+ ```
29
+
30
+ ```sh
31
+ # Applies single template.
32
+ cpl apply-template redis -a $APP_NAME
33
+
34
+ # Applies several templates (practically creating full app).
35
+ cpl apply-template gvc postgres redis rails -a $APP_NAME
36
+ ```
37
+
14
38
  ### `build-image`
15
39
 
16
40
  - Builds and pushes the image to Control Plane
17
41
  - Automatically assigns image numbers, e.g., `app:1`, `app:2`, etc.
18
- - Uses `.controlplane/Dockerfile`
42
+ - Uses `.controlplane/Dockerfile` or a different Dockerfile specified through `dockerfile` in the `.controlplane/controlplane.yml` file
43
+ - If a commit is provided through `--commit` or `-c`, it will be set as the runtime env var `GIT_COMMIT`
19
44
 
20
45
  ```sh
21
46
  cpl build-image -a $APP_NAME
@@ -143,6 +168,51 @@ cpl logs -a $APP_NAME
143
168
  cpl logs -a $APP_NAME -w $WORKLOAD_NAME
144
169
  ```
145
170
 
171
+ ### `maintenance`
172
+
173
+ - Checks if maintenance mode is on or off for an app
174
+ - Outputs 'on' or 'off'
175
+ - Specify the one-off workload through `one_off_workload` in the `.controlplane/controlplane.yml` file
176
+ - Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
177
+ - Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
178
+
179
+ ```sh
180
+ cpl maintenance -a $APP_NAME
181
+ ```
182
+
183
+ ### `maintenance:off`
184
+
185
+ - Disables maintenance mode for an app
186
+ - Specify the one-off workload through `one_off_workload` in the `.controlplane/controlplane.yml` file
187
+ - Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
188
+ - Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
189
+
190
+ ```sh
191
+ cpl maintenance:off -a $APP_NAME
192
+ ```
193
+
194
+ ### `maintenance:on`
195
+
196
+ - Enables maintenance mode for an app
197
+ - Specify the one-off workload through `one_off_workload` in the `.controlplane/controlplane.yml` file
198
+ - Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
199
+ - Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
200
+
201
+ ```sh
202
+ cpl maintenance:on -a $APP_NAME
203
+ ```
204
+
205
+ ### `maintenance:set-page`
206
+
207
+ - Sets the page for maintenance mode
208
+ - Only works if the maintenance workload uses the `shakacode/maintenance-mode` image
209
+ - Will set the URL as an env var `PAGE_URL` on the maintenance workload
210
+ - Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
211
+
212
+ ```sh
213
+ cpl maintenance:set-page PAGE_URL -a $APP_NAME
214
+ ```
215
+
146
216
  ### `open`
147
217
 
148
218
  - Opens the app endpoint URL in the default browser
@@ -220,6 +290,7 @@ cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
220
290
  - Runs one-off **_interactive_** replicas (analog of `heroku run`)
221
291
  - Uses `Standard` workload type and `cpln exec` as the execution method, with CLI streaming
222
292
  - May not work correctly with tasks that last over 5 minutes (there's a Control Plane scaling bug at the moment)
293
+ - If `fix_terminal_size` is `true` in the `.controlplane/controlplane.yml` file, the remote terminal size will be fixed to match the local terminal size (may also be overriden through `--terminal-size`)
223
294
 
224
295
  > **IMPORTANT:** Useful for development where it's needed for interaction, and where network connection drops and
225
296
  > task crashing are tolerable. For production tasks, it's better to use `cpl run:detached`.
@@ -228,6 +299,12 @@ cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
228
299
  # Opens shell (bash by default).
229
300
  cpl run -a $APP_NAME
230
301
 
302
+ # Need to quote COMMAND if setting ENV value or passing args.
303
+ cpl run 'LOG_LEVEL=warn rails db:migrate' -a $APP_NAME
304
+
305
+ # COMMAND may also be passed at the end (in this case, no need to quote).
306
+ cpl run -a $APP_NAME -- rails db:migrate
307
+
231
308
  # Runs command, displays output, and exits shell.
232
309
  cpl run ls / -a $APP_NAME
233
310
  cpl run rails db:migrate:status -a $APP_NAME
@@ -238,6 +315,24 @@ cpl run rails c -a $APP_NAME
238
315
  # Uses a different image (which may not be promoted yet).
239
316
  cpl run rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
240
317
  cpl run rails db:migrate -a $APP_NAME --image latest # Latest sequential image
318
+
319
+ # Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
320
+ cpl run bash -a $APP_NAME -w other-workload
321
+
322
+ # Overrides remote CPLN_TOKEN env variable with local token.
323
+ # Useful when superuser rights are needed in remote container.
324
+ cpl run bash -a $APP_NAME --use-local-token
325
+ ```
326
+
327
+ ### `run:cleanup`
328
+
329
+ - Deletes stale run workloads for an app
330
+ - Workloads are considered stale based on how many days since created
331
+ - `stale_run_workload_created_days` in the `.controlplane/controlplane.yml` file specifies the number of days after created that the workload is considered stale
332
+ - Will ask for explicit user confirmation of deletion
333
+
334
+ ```sh
335
+ cpl run:cleanup -a $APP_NAME
241
336
  ```
242
337
 
243
338
  ### `run:detached`
@@ -251,9 +346,12 @@ cpl run rails db:migrate -a $APP_NAME --image latest # Latest sequential i
251
346
  ```sh
252
347
  cpl run:detached rails db:prepare -a $APP_NAME
253
348
 
254
- # Need to quote COMMAND if setting ENV value or passing args to command to run
349
+ # Need to quote COMMAND if setting ENV value or passing args.
255
350
  cpl run:detached 'LOG_LEVEL=warn rails db:migrate' -a $APP_NAME
256
351
 
352
+ # COMMAND may also be passed at the end (in this case, no need to quote).
353
+ cpl run:detached -a $APP_NAME -- rails db:migrate
354
+
257
355
  # Uses some other image.
258
356
  cpl run:detached rails db:migrate -a $APP_NAME --image /some/full/image/path
259
357
 
@@ -263,30 +361,19 @@ cpl run:detached rails db:migrate -a $APP_NAME --image latest
263
361
  # Uses a different image (which may not be promoted yet).
264
362
  cpl run:detached rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
265
363
  cpl run:detached rails db:migrate -a $APP_NAME --image latest # Latest sequential image
364
+
365
+ # Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
366
+ cpl run:detached rails db:migrate:status -a $APP_NAME -w other-workload
266
367
  ```
267
368
 
268
- ### `setup`
369
+ ### `setup-app`
269
370
 
270
- - Applies application-specific configs from templates (e.g., for every review-app)
271
- - Publishes (creates or updates) those at Control Plane infrastructure
272
- - Picks templates from the `.controlplane/templates` directory
273
- - Templates are ordinary Control Plane templates but with variable preprocessing
274
-
275
- **Preprocessed template variables:**
276
-
277
- ```
278
- APP_GVC - basically GVC or app name
279
- APP_LOCATION - default location
280
- APP_ORG - organization
281
- APP_IMAGE - will use latest app image
282
- ```
371
+ - Creates an app and all its workloads
372
+ - Specify the templates for the app and workloads through `setup` in the `.controlplane/controlplane.yml` file
373
+ - This should should only be used for temporary apps like review apps, never for persistent apps like production (to update workloads for those, use 'cpl apply-template' instead)
283
374
 
284
375
  ```sh
285
- # Applies single template.
286
- cpl setup redis -a $APP_NAME
287
-
288
- # Applies several templates (practically creating full app).
289
- cpl setup gvc postgres redis rails -a $APP_NAME
376
+ cpl setup-app -a $APP_NAME
290
377
  ```
291
378
 
292
379
  ### `version`
@@ -66,7 +66,7 @@ build-review-app:
66
66
  name: Provision review app if needed
67
67
  command: |
68
68
  if ! cpl exist -a ${APP_NAME}; then
69
- cpl setup gvc postgres redis memcached rails sidekiq -a ${APP_NAME}
69
+ cpl setup-app -a ${APP_NAME}
70
70
  echo "export NEW_APP=true" >> $BASH_ENV
71
71
  fi
72
72
  - run:
@@ -23,6 +23,9 @@ aliases:
23
23
  - postgres
24
24
  - memcached
25
25
 
26
+ # Configure the workload name used when maintenance mode is on (defaults to 'maintenance')
27
+ maintenance_workload: maintenance
28
+
26
29
  apps:
27
30
  my-app-staging:
28
31
  # Use the values from the common section above
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Command
4
- class Setup < Base
5
- NAME = "setup"
6
- USAGE = "setup TEMPLATE [TEMPLATE] ... [TEMPLATE]"
4
+ class ApplyTemplate < Base # rubocop:disable Metrics/ClassLength
5
+ NAME = "apply-template"
6
+ USAGE = "apply-template TEMPLATE [TEMPLATE] ... [TEMPLATE]"
7
7
  REQUIRES_ARGS = true
8
8
  OPTIONS = [
9
- app_option(required: true)
9
+ app_option(required: true),
10
+ skip_confirm_option
10
11
  ].freeze
11
12
  DESCRIPTION = "Applies application-specific configs from templates"
12
13
  LONG_DESCRIPTION = <<~DESC
@@ -27,28 +28,35 @@ module Command
27
28
  EXAMPLES = <<~EX
28
29
  ```sh
29
30
  # Applies single template.
30
- cpl setup redis -a $APP_NAME
31
+ cpl apply-template redis -a $APP_NAME
31
32
 
32
33
  # Applies several templates (practically creating full app).
33
- cpl setup gvc postgres redis rails -a $APP_NAME
34
+ cpl apply-template gvc postgres redis rails -a $APP_NAME
34
35
  ```
35
36
  EX
36
37
 
37
38
  def call # rubocop:disable Metrics/MethodLength
39
+ ensure_templates!
40
+
38
41
  @app_status = :existing
39
42
  @created_workloads = []
40
43
  @failed_workloads = []
44
+ @skipped_workloads = []
41
45
 
42
- config.args.each do |template|
43
- filename = "#{config.app_cpln_dir}/templates/#{template}.yml"
46
+ @asked_for_confirmation = false
44
47
 
45
- step("Applying template '#{template}'", abort_on_error: false) do
46
- unless File.exist?(filename)
47
- report_failure(template)
48
+ pending_templates = templates.select do |template|
49
+ if template == "gvc"
50
+ confirm_app(template)
51
+ else
52
+ confirm_workload(template)
53
+ end
54
+ end
48
55
 
49
- raise "Can't find template '#{template}' at '#{filename}', please create it."
50
- end
56
+ progress.puts if @asked_for_confirmation
51
57
 
58
+ pending_templates.each do |template, filename|
59
+ step("Applying template '#{template}'", abort_on_error: false) do
52
60
  apply_template(filename)
53
61
  if $CHILD_STATUS.success?
54
62
  report_success(template)
@@ -63,10 +71,58 @@ module Command
63
71
  print_app_status
64
72
  print_created_workloads
65
73
  print_failed_workloads
74
+ print_skipped_workloads
66
75
  end
67
76
 
68
77
  private
69
78
 
79
+ def templates
80
+ @templates ||= config.args.to_h do |template|
81
+ [template, "#{config.app_cpln_dir}/templates/#{template}.yml"]
82
+ end
83
+ end
84
+
85
+ def ensure_templates!
86
+ missing_templates = templates.filter { |_template, filename| !File.exist?(filename) }.to_h
87
+ return if missing_templates.empty?
88
+
89
+ missing_templates_str = missing_templates.map do |template, filename|
90
+ " - #{template} (#{filename})"
91
+ end.join("\n")
92
+ progress.puts("#{Shell.color('Missing templates:', :red)}\n#{missing_templates_str}\n\n")
93
+
94
+ raise "Can't find templates above, please create them."
95
+ end
96
+
97
+ def confirm_apply(message)
98
+ return true if config.options[:yes]
99
+
100
+ @asked_for_confirmation = true
101
+ Shell.confirm(message)
102
+ end
103
+
104
+ def confirm_app(template)
105
+ app = cp.fetch_gvc
106
+ return true unless app
107
+
108
+ confirmed = confirm_apply("App '#{config.app}' already exists, do you want to re-create it?")
109
+ return true if confirmed
110
+
111
+ report_skipped(template)
112
+ false
113
+ end
114
+
115
+ def confirm_workload(template)
116
+ workload = cp.fetch_workload(template)
117
+ return true unless workload
118
+
119
+ confirmed = confirm_apply("Workload '#{template}' already exists, do you want to re-create it?")
120
+ return true if confirmed
121
+
122
+ report_skipped(template)
123
+ false
124
+ end
125
+
70
126
  def apply_template(filename)
71
127
  data = File.read(filename)
72
128
  .gsub("APP_GVC", config.app)
@@ -93,13 +149,24 @@ module Command
93
149
  end
94
150
  end
95
151
 
152
+ def report_skipped(template)
153
+ if template == "gvc"
154
+ @app_status = :skipped
155
+ else
156
+ @skipped_workloads.push(template)
157
+ end
158
+ end
159
+
96
160
  def print_app_status
97
161
  return if @app_status == :existing
98
162
 
99
- if @app_status == :success
163
+ case @app_status
164
+ when :success
100
165
  progress.puts("\n#{Shell.color("Created app '#{config.app}'.", :green)}")
101
- else
166
+ when :failure
102
167
  progress.puts("\n#{Shell.color("Failed to create app '#{config.app}'.", :red)}")
168
+ when :skipped
169
+ progress.puts("\n#{Shell.color("Skipped app '#{config.app}' (already exists).", :blue)}")
103
170
  end
104
171
  end
105
172
 
@@ -116,5 +183,12 @@ module Command
116
183
  workloads = @failed_workloads.map { |template| " - #{template}" }.join("\n")
117
184
  progress.puts("\n#{Shell.color('Failed to create workloads:', :red)}\n#{workloads}")
118
185
  end
186
+
187
+ def print_skipped_workloads
188
+ return unless @skipped_workloads.any?
189
+
190
+ workloads = @skipped_workloads.map { |template| " - #{template}" }.join("\n")
191
+ progress.puts("\n#{Shell.color('Skipped workloads (already exist):', :blue)}\n#{workloads}")
192
+ end
119
193
  end
120
194
  end