cpl 0.5.1 → 0.7.0

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: 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