cpl 0.6.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/command_docs.yml +24 -0
- data/.github/workflows/rspec.yml +8 -5
- data/.github/workflows/rubocop.yml +5 -2
- data/.overcommit.yml +3 -0
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +18 -3
- data/README.md +67 -20
- data/Rakefile +9 -4
- data/cpl.gemspec +3 -0
- data/docs/commands.md +72 -5
- data/examples/circleci.yml +1 -1
- data/examples/controlplane.yml +3 -0
- data/lib/command/base.rb +61 -28
- data/lib/command/build_image.rb +15 -3
- data/lib/command/copy_image_from_upstream.rb +1 -1
- data/lib/command/info.rb +9 -5
- data/lib/command/maintenance.rb +37 -0
- data/lib/command/maintenance_off.rb +58 -0
- data/lib/command/maintenance_on.rb +58 -0
- data/lib/command/maintenance_set_page.rb +34 -0
- data/lib/command/no_command.rb +1 -1
- data/lib/command/promote_app_from_upstream.rb +2 -2
- data/lib/command/ps_start.rb +22 -5
- data/lib/command/ps_stop.rb +22 -5
- data/lib/command/run.rb +30 -10
- data/lib/command/run_cleanup.rb +99 -0
- data/lib/command/run_detached.rb +18 -11
- data/lib/command/setup_app.rb +3 -3
- data/lib/core/config.rb +39 -32
- data/lib/core/controlplane.rb +72 -16
- data/lib/core/controlplane_api.rb +39 -0
- data/lib/core/controlplane_api_direct.rb +13 -3
- data/lib/core/scripts.rb +2 -2
- data/lib/cpl/version.rb +1 -1
- data/script/check_command_docs +3 -0
- data/templates/daily-task.yml +30 -0
- data/templates/maintenance.yml +24 -0
- metadata +54 -3
- /data/script/{generate_commands_docs → update_command_docs} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 410e8bfdc923cabc36b900bb6cc3bb98e586cc2789579ec01cc33fe9c9c39fe1
|
4
|
+
data.tar.gz: a7428c35cff0dabcd1c68469561b82e2c3f24282b92dba9b1eeeb94c51d9d654
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c09fb9477e7dd638220e4ad711161a176daab7e82ed7224d584b6617989e3dd789ae5f66eb75e0086bdcd9690d680e2de668b5698ce322184ecdd23522835a3
|
7
|
+
data.tar.gz: 82f3a8aaf6b465850f9b577c5f7aed1b8b4313bf0224d52f058fc94e17f334a9cb9f51bb2638600c150184714fb254c2edeea1bb1f77b40a976fe20d0db11b54
|
@@ -0,0 +1,24 @@
|
|
1
|
+
name: Command Docs
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- main
|
7
|
+
pull_request:
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
rspec:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
name: Command Docs
|
13
|
+
steps:
|
14
|
+
- name: Checkout code
|
15
|
+
uses: actions/checkout@v3
|
16
|
+
- name: Set up Ruby
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: "3.0"
|
20
|
+
bundler-cache: true
|
21
|
+
- name: Install dependencies
|
22
|
+
run: bundle install
|
23
|
+
- name: Check if command docs are up to date
|
24
|
+
run: bundle exec rake check_command_docs
|
data/.github/workflows/rspec.yml
CHANGED
@@ -8,15 +8,18 @@ on:
|
|
8
8
|
|
9
9
|
jobs:
|
10
10
|
rspec:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
name: RSpec
|
13
|
-
env:
|
14
|
-
RAILS_ENV: test
|
15
11
|
strategy:
|
16
12
|
matrix:
|
13
|
+
os:
|
14
|
+
- ubuntu-latest
|
15
|
+
- macos-latest
|
17
16
|
ruby:
|
18
17
|
- "2.7"
|
19
18
|
- "3.0"
|
19
|
+
runs-on: ${{ matrix.os }}
|
20
|
+
name: RSpec
|
21
|
+
env:
|
22
|
+
RAILS_ENV: test
|
20
23
|
steps:
|
21
24
|
- name: Checkout code
|
22
25
|
uses: actions/checkout@v3
|
@@ -28,7 +31,7 @@ jobs:
|
|
28
31
|
- name: Install dependencies
|
29
32
|
run: bundle install
|
30
33
|
- name: Run tests
|
31
|
-
run: bundle exec rspec
|
34
|
+
run: bundle exec rspec
|
32
35
|
- name: Upload coverage results
|
33
36
|
uses: actions/upload-artifact@master
|
34
37
|
if: always()
|
@@ -8,13 +8,16 @@ on:
|
|
8
8
|
|
9
9
|
jobs:
|
10
10
|
rubocop:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
name: Rubocop
|
13
11
|
strategy:
|
14
12
|
matrix:
|
13
|
+
os:
|
14
|
+
- ubuntu-latest
|
15
|
+
- macos-latest
|
15
16
|
ruby:
|
16
17
|
- "2.7"
|
17
18
|
- "3.0"
|
19
|
+
runs-on: ${{ matrix.os }}
|
20
|
+
name: Rubocop
|
18
21
|
steps:
|
19
22
|
- name: Checkout code
|
20
23
|
uses: actions/checkout@v3
|
data/.overcommit.yml
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cpl (0.
|
4
|
+
cpl (1.0.0)
|
5
5
|
debug (~> 1.7.1)
|
6
6
|
dotenv (~> 2.8.1)
|
7
7
|
psych (~> 5.1.0)
|
@@ -10,14 +10,19 @@ 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
28
|
irb (1.6.4)
|
@@ -32,10 +37,11 @@ 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)
|
38
|
-
reline (0.3.
|
44
|
+
reline (0.3.4)
|
39
45
|
io-console (~> 0.5)
|
40
46
|
rexml (3.2.5)
|
41
47
|
rspec (3.12.0)
|
@@ -78,8 +84,14 @@ GEM
|
|
78
84
|
simplecov-html (0.12.3)
|
79
85
|
simplecov_json_formatter (0.1.4)
|
80
86
|
stringio (3.0.6)
|
81
|
-
thor (1.2.
|
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. [
|
32
|
-
10. [
|
33
|
-
11. [
|
34
|
-
12. [
|
35
|
-
13. [Migrating
|
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`
|
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
|
-
|
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
|
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,13 +4,18 @@ require "bundler/gem_tasks"
|
|
4
4
|
require "rspec/core/rake_task"
|
5
5
|
require "rubocop/rake_task"
|
6
6
|
|
7
|
-
RSpec::Core::RakeTask.new(:
|
7
|
+
RSpec::Core::RakeTask.new(:rspec)
|
8
8
|
|
9
9
|
RuboCop::RakeTask.new
|
10
10
|
|
11
|
-
task default: %i[
|
11
|
+
task default: %i[rspec rubocop]
|
12
|
+
|
13
|
+
desc "Checks if commands.md file is up to date"
|
14
|
+
task :check_command_docs do
|
15
|
+
sh "./script/check_command_docs"
|
16
|
+
end
|
12
17
|
|
13
18
|
desc "Updates commands.md file"
|
14
|
-
task :
|
15
|
-
sh "./script/
|
19
|
+
task :update_command_docs do
|
20
|
+
sh "./script/update_command_docs"
|
16
21
|
end
|
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
@@ -39,7 +39,8 @@ cpl apply-template gvc postgres redis rails -a $APP_NAME
|
|
39
39
|
|
40
40
|
- Builds and pushes the image to Control Plane
|
41
41
|
- Automatically assigns image numbers, e.g., `app:1`, `app:2`, etc.
|
42
|
-
- 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`
|
43
44
|
|
44
45
|
```sh
|
45
46
|
cpl build-image -a $APP_NAME
|
@@ -167,6 +168,51 @@ cpl logs -a $APP_NAME
|
|
167
168
|
cpl logs -a $APP_NAME -w $WORKLOAD_NAME
|
168
169
|
```
|
169
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
|
+
|
170
216
|
### `open`
|
171
217
|
|
172
218
|
- Opens the app endpoint URL in the default browser
|
@@ -244,6 +290,7 @@ cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
|
|
244
290
|
- Runs one-off **_interactive_** replicas (analog of `heroku run`)
|
245
291
|
- Uses `Standard` workload type and `cpln exec` as the execution method, with CLI streaming
|
246
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`)
|
247
294
|
|
248
295
|
> **IMPORTANT:** Useful for development where it's needed for interaction, and where network connection drops and
|
249
296
|
> task crashing are tolerable. For production tasks, it's better to use `cpl run:detached`.
|
@@ -252,6 +299,12 @@ cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
|
|
252
299
|
# Opens shell (bash by default).
|
253
300
|
cpl run -a $APP_NAME
|
254
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
|
+
|
255
308
|
# Runs command, displays output, and exits shell.
|
256
309
|
cpl run ls / -a $APP_NAME
|
257
310
|
cpl run rails db:migrate:status -a $APP_NAME
|
@@ -263,14 +316,25 @@ cpl run rails c -a $APP_NAME
|
|
263
316
|
cpl run rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
|
264
317
|
cpl run rails db:migrate -a $APP_NAME --image latest # Latest sequential image
|
265
318
|
|
266
|
-
# Uses a different workload
|
319
|
+
# Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
|
267
320
|
cpl run bash -a $APP_NAME -w other-workload
|
268
321
|
|
269
322
|
# Overrides remote CPLN_TOKEN env variable with local token.
|
270
|
-
# Useful when
|
323
|
+
# Useful when superuser rights are needed in remote container.
|
271
324
|
cpl run bash -a $APP_NAME --use-local-token
|
272
325
|
```
|
273
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
|
336
|
+
```
|
337
|
+
|
274
338
|
### `run:detached`
|
275
339
|
|
276
340
|
- Runs one-off **_non-interactive_** replicas (close analog of `heroku run:detached`)
|
@@ -282,9 +346,12 @@ cpl run bash -a $APP_NAME --use-local-token
|
|
282
346
|
```sh
|
283
347
|
cpl run:detached rails db:prepare -a $APP_NAME
|
284
348
|
|
285
|
-
# Need to quote COMMAND if setting ENV value or passing args
|
349
|
+
# Need to quote COMMAND if setting ENV value or passing args.
|
286
350
|
cpl run:detached 'LOG_LEVEL=warn rails db:migrate' -a $APP_NAME
|
287
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
|
+
|
288
355
|
# Uses some other image.
|
289
356
|
cpl run:detached rails db:migrate -a $APP_NAME --image /some/full/image/path
|
290
357
|
|
@@ -295,7 +362,7 @@ cpl run:detached rails db:migrate -a $APP_NAME --image latest
|
|
295
362
|
cpl run:detached rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
|
296
363
|
cpl run:detached rails db:migrate -a $APP_NAME --image latest # Latest sequential image
|
297
364
|
|
298
|
-
# Uses a different workload
|
365
|
+
# Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
|
299
366
|
cpl run:detached rails db:migrate:status -a $APP_NAME -w other-workload
|
300
367
|
```
|
301
368
|
|
data/examples/circleci.yml
CHANGED
@@ -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
|
69
|
+
cpl setup-app -a ${APP_NAME}
|
70
70
|
echo "export NEW_APP=true" >> $BASH_ENV
|
71
71
|
fi
|
72
72
|
- run:
|
data/examples/controlplane.yml
CHANGED
data/lib/command/base.rb
CHANGED
@@ -153,6 +153,29 @@ module Command
|
|
153
153
|
}
|
154
154
|
end
|
155
155
|
|
156
|
+
def self.terminal_size_option(required: false)
|
157
|
+
{
|
158
|
+
name: :terminal_size,
|
159
|
+
params: {
|
160
|
+
banner: "ROWS,COLS",
|
161
|
+
desc: "Override remote terminal size (e.g. `--terminal-size 10,20`)",
|
162
|
+
type: :string,
|
163
|
+
required: required
|
164
|
+
}
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.wait_option(title = "", required: false)
|
169
|
+
{
|
170
|
+
name: :wait,
|
171
|
+
params: {
|
172
|
+
desc: "Waits for #{title}",
|
173
|
+
type: :boolean,
|
174
|
+
required: required
|
175
|
+
}
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
156
179
|
def self.all_options
|
157
180
|
methods.grep(/_option$/).map { |method| send(method.to_s) }
|
158
181
|
end
|
@@ -164,28 +187,22 @@ module Command
|
|
164
187
|
end
|
165
188
|
end
|
166
189
|
|
167
|
-
def wait_for(title)
|
168
|
-
progress.print "- Waiting for #{title}"
|
169
|
-
until yield
|
170
|
-
progress.print(".")
|
171
|
-
sleep(1)
|
172
|
-
end
|
173
|
-
progress.puts
|
174
|
-
end
|
175
|
-
|
176
190
|
def wait_for_workload(workload)
|
177
|
-
|
191
|
+
step("Waiting for workload", retry_on_failure: true) do
|
192
|
+
cp.fetch_workload(workload)
|
193
|
+
end
|
178
194
|
end
|
179
195
|
|
180
196
|
def wait_for_replica(workload, location)
|
181
|
-
|
197
|
+
step("Waiting for replica", retry_on_failure: true) do
|
182
198
|
cp.workload_get_replicas_safely(workload, location: location)&.dig("items", 0)
|
183
199
|
end
|
184
200
|
end
|
185
201
|
|
186
202
|
def ensure_workload_deleted(workload)
|
187
|
-
|
188
|
-
|
203
|
+
step("Deleting workload") do
|
204
|
+
cp.delete_workload(workload)
|
205
|
+
end
|
189
206
|
end
|
190
207
|
|
191
208
|
def latest_image_from(items, app_name: config.app, name_only: true)
|
@@ -212,8 +229,9 @@ module Command
|
|
212
229
|
def latest_image_next(app = config.app, org = config.org)
|
213
230
|
@latest_image_next ||= {}
|
214
231
|
@latest_image_next[app] ||= begin
|
215
|
-
|
216
|
-
image
|
232
|
+
latest_image_name = latest_image(app, org)
|
233
|
+
image = latest_image_name.split(":").first
|
234
|
+
image += ":#{extract_image_number(latest_image_name) + 1}"
|
217
235
|
image += "_#{config.options[:commit]}" if config.options[:commit]
|
218
236
|
image
|
219
237
|
end
|
@@ -229,29 +247,44 @@ module Command
|
|
229
247
|
$stderr
|
230
248
|
end
|
231
249
|
|
232
|
-
def
|
250
|
+
def step_error(error, abort_on_error: true)
|
251
|
+
message = error.message
|
252
|
+
if abort_on_error
|
253
|
+
progress.puts(" #{Shell.color('failed!', :red)}\n\n")
|
254
|
+
Shell.abort(message)
|
255
|
+
else
|
256
|
+
Shell.write_to_tmp_stderr(message)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def step_finish(success)
|
261
|
+
if success
|
262
|
+
progress.puts(" #{Shell.color('done!', :green)}")
|
263
|
+
else
|
264
|
+
progress.puts(" #{Shell.color('failed!', :red)}\n\n#{Shell.read_from_tmp_stderr}\n\n")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def step(message, abort_on_error: true, retry_on_failure: false) # rubocop:disable Metrics/MethodLength
|
233
269
|
progress.print("#{message}...")
|
234
270
|
|
235
271
|
Shell.use_tmp_stderr do
|
236
272
|
success = false
|
237
273
|
|
238
274
|
begin
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
Shell.abort(message)
|
275
|
+
if retry_on_failure
|
276
|
+
until (success = yield)
|
277
|
+
progress.print(".")
|
278
|
+
sleep 1
|
279
|
+
end
|
245
280
|
else
|
246
|
-
|
281
|
+
success = yield
|
247
282
|
end
|
283
|
+
rescue RuntimeError => e
|
284
|
+
step_error(e, abort_on_error: abort_on_error)
|
248
285
|
end
|
249
286
|
|
250
|
-
|
251
|
-
progress.puts(" #{Shell.color('done!', :green)}")
|
252
|
-
else
|
253
|
-
progress.puts(" #{Shell.color('failed!', :red)}\n\n#{Shell.read_from_tmp_stderr}\n\n")
|
254
|
-
end
|
287
|
+
step_finish(success)
|
255
288
|
end
|
256
289
|
end
|
257
290
|
|
data/lib/command/build_image.rb
CHANGED
@@ -11,18 +11,30 @@ module Command
|
|
11
11
|
LONG_DESCRIPTION = <<~DESC
|
12
12
|
- Builds and pushes the image to Control Plane
|
13
13
|
- Automatically assigns image numbers, e.g., `app:1`, `app:2`, etc.
|
14
|
-
- Uses `.controlplane/Dockerfile`
|
14
|
+
- Uses `.controlplane/Dockerfile` or a different Dockerfile specified through `dockerfile` in the `.controlplane/controlplane.yml` file
|
15
|
+
- If a commit is provided through `--commit` or `-c`, it will be set as the runtime env var `GIT_COMMIT`
|
15
16
|
DESC
|
16
17
|
|
17
|
-
def call
|
18
|
+
def call # rubocop:disable Metrics/MethodLength
|
18
19
|
ensure_docker_running!
|
19
20
|
|
20
21
|
dockerfile = config.current[:dockerfile] || "Dockerfile"
|
21
22
|
dockerfile = "#{config.app_cpln_dir}/#{dockerfile}"
|
22
23
|
|
24
|
+
raise "Can't find Dockerfile at '#{dockerfile}'." unless File.exist?(dockerfile)
|
25
|
+
|
23
26
|
progress.puts("Building image from Dockerfile '#{dockerfile}'...\n\n")
|
24
27
|
|
25
|
-
|
28
|
+
image_name = latest_image_next
|
29
|
+
image_url = "#{config.org}.registry.cpln.io/#{image_name}"
|
30
|
+
|
31
|
+
commit = config.options[:commit]
|
32
|
+
build_args = []
|
33
|
+
build_args.push("GIT_COMMIT=#{commit}") if commit
|
34
|
+
|
35
|
+
cp.image_build(image_url, dockerfile: dockerfile, build_args: build_args)
|
36
|
+
|
37
|
+
progress.puts("\nPushed image to '/org/#{config.org}/image/#{image_name}'.")
|
26
38
|
end
|
27
39
|
|
28
40
|
private
|
@@ -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]
|
33
33
|
ensure_upstream_org!
|
34
34
|
|
35
35
|
create_upstream_profile
|