cpl 0.1.0 → 0.2.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: 2392653f1a75e0dc398590cc5c0e9d89d4769a50af3432b2861e01ff794e8cda
4
- data.tar.gz: 13c33cc6465394b90b1fd8e94f711c98135bfdcb25756db7d3b7b0c8bfc819fa
3
+ metadata.gz: 940fc95a21ea2771a453b12e646d182ed42ef448fd83081ac822af26d1820ad3
4
+ data.tar.gz: 4405dd3555275a1bbe135d52abaf072ed683cb183d0ee36e0060c38262ca8017
5
5
  SHA512:
6
- metadata.gz: bc2b5f2555b8f329ad8d5b2be9f5762e6f265f499baaa035e65c24257b47c26459842f2611ee8d352af65b3dcabf4f0e6570007c59f5ca543f3edb382ed04747
7
- data.tar.gz: 904028e00550311c8b9327fb3a17a8a00c75b4806e81ca8359d5b3f6ae55b19f8a89efbc3ccc087e4f62e2243930587df1f693ebbbac9470377b0e6905e0dd19
6
+ metadata.gz: 579a48aff74172dfe8ac8652e3538006d897ad2ce82459869227889d1e294595c0a698f846f2fe9db3970950e1f0372a6149f75ce06f6a2ab526fa451fea6649
7
+ data.tar.gz: 26581dbe132fea73f6066ba4a030738a1b08978e17d02fe6ba95ebed74d879f25a103ce5ddbeff8ba33c4508d7b302fc9f28c0d822f77c423c74c07cdf95006b
@@ -1,4 +1,4 @@
1
- name: CI
1
+ name: RSpec
2
2
 
3
3
  on:
4
4
  push:
@@ -7,29 +7,7 @@ on:
7
7
  pull_request:
8
8
 
9
9
  jobs:
10
- rubocop:
11
- runs-on: ubuntu-latest
12
- name: Rubocop
13
- strategy:
14
- matrix:
15
- ruby:
16
- - "2.7"
17
- - "3.0"
18
- steps:
19
- - name: Checkout code
20
- uses: actions/checkout@v3
21
- - name: Set up Ruby
22
- uses: ruby/setup-ruby@v1
23
- with:
24
- ruby-version: ${{ matrix.ruby }}
25
- rubygems: latest
26
- - name: Install dependencies
27
- run: bundle install
28
- - name: Analyze code
29
- run: bundle exec rubocop
30
-
31
10
  rspec:
32
- needs: rubocop
33
11
  runs-on: ubuntu-latest
34
12
  name: RSpec
35
13
  env:
@@ -46,8 +24,7 @@ jobs:
46
24
  uses: ruby/setup-ruby@v1
47
25
  with:
48
26
  ruby-version: ${{ matrix.ruby }}
49
- rubygems: latest
50
- bundler-cache: false
27
+ bundler-cache: true
51
28
  - name: Install dependencies
52
29
  run: bundle install
53
30
  - name: Run tests
@@ -0,0 +1,29 @@
1
+ name: Rubocop
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+
9
+ jobs:
10
+ rubocop:
11
+ runs-on: ubuntu-latest
12
+ name: Rubocop
13
+ strategy:
14
+ matrix:
15
+ ruby:
16
+ - "2.7"
17
+ - "3.0"
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v3
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: true
26
+ - name: Install dependencies
27
+ run: bundle install
28
+ - name: Analyze code
29
+ run: bundle exec rubocop
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
- ## [Unreleased]
1
+ # Changelog
2
2
 
3
- ## [0.1.0] - 2023-02-08
3
+ ## 0.1.1 - 2023-03-09
4
+
5
+ - Fixed issue with default gems for older Ruby versions (#14)
6
+
7
+ ## 0.1.0 - 2023-02-19
4
8
 
5
9
  - Initial release
data/CONTRIBUTING.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Contributing
2
2
 
3
+ ## Installation
4
+ Rather than installing `cpl` as a Ruby gem, install this repo locally and alias `cpl` command globally for easier access, e.g.:
5
+
6
+ ```sh
7
+ git clone https://github.com/shakacode/heroku-to-control-plane
8
+
9
+ # Create an alias in some local shell startup script, e.g., `.profile`, `.bashrc`, etc.
10
+ alias cpl="~/projects/heroku-to-control-plane/cpl"
11
+ ```
12
+
13
+ Or set the path of the Ruby gem in your Gemfile.
14
+
15
+ ```ruby
16
+ gem 'cpl', path: '~/projects/heroku-to-control-plane'
17
+ ```
18
+
3
19
  ## Linting
4
20
  Be sure to run `rubocop -a` before committing code.
5
21
 
data/Gemfile.lock CHANGED
@@ -1,23 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (0.1.0)
5
- cgi (~> 0.3.6)
4
+ cpl (0.1.1)
6
5
  debug (~> 1.7.1)
7
6
  dotenv (~> 2.8.1)
8
- json (~> 2.6.3)
9
- net-http (~> 0.3.2)
10
- pathname (~> 0.2.1)
11
7
  psych (~> 5.1.0)
12
- tempfile (~> 0.1.3)
13
8
  thor (~> 1.2.1)
14
- yaml (~> 0.2.1)
15
9
 
16
10
  GEM
17
11
  remote: https://rubygems.org/
18
12
  specs:
19
13
  ast (2.4.2)
20
- cgi (0.3.6)
21
14
  debug (1.7.1)
22
15
  irb (>= 1.5.0)
23
16
  reline (>= 0.3.1)
@@ -28,12 +21,9 @@ GEM
28
21
  irb (1.6.2)
29
22
  reline (>= 0.3.0)
30
23
  json (2.6.3)
31
- net-http (0.3.2)
32
- uri
33
24
  parallel (1.22.1)
34
25
  parser (3.2.0.0)
35
26
  ast (~> 2.4.1)
36
- pathname (0.2.1)
37
27
  psych (5.1.0)
38
28
  stringio
39
29
  rainbow (3.1.1)
@@ -82,11 +72,8 @@ GEM
82
72
  simplecov-html (0.12.3)
83
73
  simplecov_json_formatter (0.1.4)
84
74
  stringio (3.0.5)
85
- tempfile (0.1.3)
86
75
  thor (1.2.1)
87
76
  unicode-display_width (2.4.2)
88
- uri (0.12.0)
89
- yaml (0.2.1)
90
77
 
91
78
  PLATFORMS
92
79
  x86_64-linux
data/README.md CHANGED
@@ -1,7 +1,12 @@
1
- # Heroku to Control Plane
1
+ # Heroku to Control Plane `cpl` CLI
2
2
 
3
3
  _A playbook for migrating from [Heroku](https://heroku.com) to [Control Plane](https://controlplane.com)_
4
4
 
5
+ [![RSpec](https://github.com/shakacode/heroku-to-control-plane/actions/workflows/rspec.yml/badge.svg)](https://github.com/shakacode/heroku-to-control-plane/actions/workflows/rspec.yml)
6
+ [![Rubocop](https://github.com/shakacode/heroku-to-control-plane/actions/workflows/rubocop.yml/badge.svg)](https://github.com/shakacode/heroku-to-control-plane/actions/workflows/rubocop.yml)
7
+
8
+ [![Gem](https://badge.fury.io/rb/cpl.svg)](https://badge.fury.io/rb/cpl)
9
+
5
10
  This playbook shows how to move "Heroku apps" to "Control Plane workloads" via an open-source `cpl` CLI on top of Control Plane's `cpln` CLI.
6
11
 
7
12
  Heroku provides a UX and CLI that enables easy publishing of Ruby on Rails and other apps. This ease of use comes via many "Heroku" abstractions and naming conventions.
@@ -20,8 +25,8 @@ To simplify migration to and usage of Control Plane for Heroku users, this repos
20
25
  9. [CLI commands reference](#cli-commands-reference)
21
26
  10. [Mapping of Heroku Commands to `cpl` and `cpln`](#mapping-of-heroku-commands-to-cpl-and-cpln)
22
27
  11. [Examples](#examples)
23
- 12. [Migrating Postgres database from Heroku infrastructure](/postgres.md)
24
- 13. [Migrating Redis database from Heroku infrastructure](/redis.md)
28
+ 12. [Migrating Postgres database from Heroku infrastructure](/docs/postgres.md)
29
+ 13. [Migrating Redis database from Heroku infrastructure](/docs/redis.md)
25
30
 
26
31
  ## Key features
27
32
 
@@ -69,25 +74,20 @@ For the typical Rails app, this means:
69
74
 
70
75
  ## Installation
71
76
 
72
- **Note:** `cpl` CLI is configured via a local clone clone of this repo. We may publish it later as a Ruby gem or Node package.
77
+ **Note:** `cpl` CLI is configured either a Ruby gem, [`cpl`](https://rubygems.org/gems/cpl) install or a local clone clone. For information on the latter, see [CONTRIBUTING.md](CONTRIBUTING.md).
73
78
 
74
79
  1. Install `node` (required for Control Plane CLI).
75
80
  2. Install `ruby` (required for these helpers).
76
- 3. Install Control Plane CLI (adds `cpln` command) and configure credentials.
81
+ 3. Install Control Plane CLI (adds `cpln` command) and configure credentials by running command `cpln login`.
77
82
 
78
83
  ```sh
79
84
  npm install -g @controlplane/cli
80
85
  cpln login
81
86
  ```
82
87
 
83
- 4. Install this repo locally and alias `cpl` command globally for easier access, e.g.:
88
+ ## Tips
89
+ Do not confuse the `cpl` CLI with the `cpln` CLI. The `cpl` CLI is the Heroku to Control Plane playbook CLI. The `cpln` CLI is the Control Plane CLI.
84
90
 
85
- ```sh
86
- git clone https://github.com/shakacode/heroku-to-control-plane
87
-
88
- # Create an alias in some local shell startup script, e.g., `.profile`, `.bashrc`, etc.
89
- alias cpl="~/projects/heroku-to-control-plane/cpl"
90
- ```
91
91
 
92
92
  - For each Git project that you want to deploy to Control Plane, copy project-specific configs to a `.controlplane` directory at the top of your project. `cpl` will pick those up depending on which project
93
93
  folder tree it runs. Thus, this automates running several projects with different configs without explicitly switching configs.
@@ -101,6 +101,8 @@ alias cpl="~/projects/heroku-to-control-plane/cpl"
101
101
  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).
102
102
  2. Other files in the `.controlplane/templates` directory are used by the `cpl setup` command.
103
103
 
104
+ ### Initial Setup and Deployment
105
+
104
106
  ```sh
105
107
  # Provision infrastructure (one-time-only for new apps) using templates.
106
108
  # Note how the arguments correspond to files in the `.controlplane/templates` directory.
@@ -119,6 +121,26 @@ cpl promote-image -a myapp
119
121
  cpl open -a myapp
120
122
  ```
121
123
 
124
+ ### Promoting code upgrades
125
+
126
+ ```sh
127
+ # Build and push new image with sequential image tagging, e.g. 'ror-tutorial_123'
128
+ cpl build-image -a ror-tutorial
129
+
130
+ # OR
131
+ # Build and push with sequential image tagging and commit SHA, e.g. 'ror-tutorial_123_ABCD'
132
+ cpl build-image -a ror-tutorial --commit ABCD
133
+
134
+ # Run database migrations (or other release tasks) with latest image,
135
+ # while app is still running on previous image.
136
+ # This is analogous to the release phase.
137
+ cpl runner rails db:migrate -a ror-tutorial --image latest
138
+
139
+ # Pomote latest image to app
140
+ cpl promote-image -a ror-tutorial
141
+ ```
142
+
143
+
122
144
  ## Example project modifications for Control Plane
123
145
 
124
146
  _See this for a complete example._
@@ -300,17 +322,17 @@ cpl --help
300
322
 
301
323
  **`[WIP]`**
302
324
 
303
- | Heroku Command | `cpl` or `cpln` |
304
- | ---------------------------------------------------------------------------------------------------------------- | --------------- |
305
- | `[heroku ps](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-ps-type-type)` | `cpl ps` |
306
- | `[heroku config](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-config)` | ? |
307
- | `[heroku maintenance](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-maintenance)` | ? |
308
- | `[heroku logs](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-logs)` | `cpl logs` |
309
- | `[heroku pg](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pg-database)` | ? |
310
- | `[heroku pipelines:promote](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pipelines-promote)` | `cpl promote` |
311
- | `[heroku psql](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-psql-database)` | ? |
312
- | `[heroku redis](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-redis-database)` | ? |
313
- | `[heroku releases](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-releases)` | ? |
325
+ | Heroku Command | `cpl` or `cpln` |
326
+ | -------------------------------------------------------------------------------------------------------------- | --------------- |
327
+ | [heroku ps](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-ps-type-type) | `cpl ps` |
328
+ | [heroku config](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-config) | ? |
329
+ | [heroku maintenance](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-maintenance) | ? |
330
+ | [heroku logs](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-logs) | `cpl logs` |
331
+ | [heroku pg](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pg-database) | ? |
332
+ | [heroku pipelines:promote](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-pipelines-promote) | `cpl promote` |
333
+ | [heroku psql](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-psql-database) | ? |
334
+ | [heroku redis](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-redis-database) | ? |
335
+ | [heroku releases](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-releases) | ? |
314
336
 
315
337
  ## Examples
316
338
 
data/Rakefile CHANGED
@@ -9,3 +9,8 @@ RSpec::Core::RakeTask.new(:spec)
9
9
  RuboCop::RakeTask.new
10
10
 
11
11
  task default: %i[spec rubocop]
12
+
13
+ desc "Updates commands.md file"
14
+ task :command_docs do
15
+ sh "./script/generate_commands_docs"
16
+ end
data/cpl.gemspec CHANGED
@@ -15,16 +15,10 @@ Gem::Specification.new do |spec|
15
15
 
16
16
  spec.required_ruby_version = ">= 2.7.0"
17
17
 
18
- spec.add_dependency "cgi", "~> 0.3.6"
19
18
  spec.add_dependency "debug", "~> 1.7.1"
20
19
  spec.add_dependency "dotenv", "~> 2.8.1"
21
- spec.add_dependency "json", "~> 2.6.3"
22
- spec.add_dependency "net-http", "~> 0.3.2"
23
- spec.add_dependency "pathname", "~> 0.2.1"
24
20
  spec.add_dependency "psych", "~> 5.1.0"
25
- spec.add_dependency "tempfile", "~> 0.1.3"
26
21
  spec.add_dependency "thor", "~> 1.2.1"
27
- spec.add_dependency "yaml", "~> 0.2.1"
28
22
 
29
23
  spec.add_development_dependency "rspec", "~> 3.12.0"
30
24
  spec.add_development_dependency "rubocop", "~> 1.45.0"
data/docs/commands.md CHANGED
@@ -21,6 +21,29 @@ This `-a` option is used in most of the commands and will pick all other app con
21
21
  cpl build-image -a $APP_NAME
22
22
  ```
23
23
 
24
+ ### `cleanup-old-images`
25
+
26
+ - Deletes all images for an app that are older than the specified amount of days
27
+ - Specify the amount of days through `old_image_retention_days` in the `.controlplane/controlplane.yml` file
28
+ - Will ask for explicit user confirmation
29
+ - Does not affect the latest image, regardless of how old it is
30
+
31
+ ```sh
32
+ cpl cleanup-old-images -a $APP_NAME
33
+ ```
34
+
35
+ ### `cleanup-stale-apps`
36
+
37
+ - Deletes the whole app (GVC with all workloads and all images) for all stale apps
38
+ - Stale apps are identified based on the creation date of the latest image
39
+ - Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
40
+ - If `match_if_app_name_starts_with` is `true` in the `.controlplane/controlplane.yml` file, it will delete all stale apps that start with the name
41
+ - Will ask for explicit user confirmation
42
+
43
+ ```sh
44
+ cpl cleanup-stale-apps -a $APP_NAME
45
+ ```
46
+
24
47
  ### `config`
25
48
 
26
49
  - Displays current configs (global and app-specific)
data/lib/command/base.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Command
4
4
  class Base # rubocop:disable Metrics/ClassLength
5
- attr_reader :config
5
+ attr_reader :thor_shell, :config
6
6
 
7
7
  # Used to call the command (`cpl NAME`)
8
8
  # NAME = ""
@@ -27,6 +27,7 @@ module Command
27
27
  NO_IMAGE_AVAILABLE = "NO_IMAGE_AVAILABLE"
28
28
 
29
29
  def initialize(config)
30
+ @thor_shell = Thor::Shell::Color.new
30
31
  @config = config
31
32
  end
32
33
 
@@ -90,14 +91,27 @@ module Command
90
91
  }
91
92
  end
92
93
 
94
+ def self.skip_confirm_option(required: false)
95
+ {
96
+ name: :yes,
97
+ params: {
98
+ aliases: ["-y"],
99
+ banner: "SKIP_CONFIRM",
100
+ desc: "Skip confirmation",
101
+ type: :boolean,
102
+ required: required
103
+ }
104
+ }
105
+ end
106
+
93
107
  def self.all_options
94
108
  methods.grep(/_option$/).map { |method| send(method.to_s) }
95
109
  end
96
110
 
97
- def self.all_options_key_name
111
+ def self.all_options_by_key_name
98
112
  all_options.each_with_object({}) do |option, result|
99
- option[:params][:aliases].each { |current_alias| result[current_alias.to_s] = option[:name] }
100
- result["--#{option[:name]}"] = option[:name]
113
+ option[:params][:aliases].each { |current_alias| result[current_alias.to_s] = option }
114
+ result["--#{option[:name]}"] = option
101
115
  end
102
116
  end
103
117
 
@@ -125,20 +139,23 @@ module Command
125
139
  cp.workload_delete(workload, no_raise: true)
126
140
  end
127
141
 
128
- def latest_image # rubocop:disable Metrics/MethodLength
142
+ def latest_image_from(items, app_name: config.app, name_only: true)
143
+ matching_items = items.filter { |item| item["name"].start_with?("#{app_name}:") }
144
+
145
+ # Or special string to indicate no image available
146
+ if matching_items.empty?
147
+ "#{app_name}:#{NO_IMAGE_AVAILABLE}"
148
+ else
149
+ latest_item = matching_items.max_by { |item| extract_image_number(item["name"]) }
150
+ name_only ? latest_item["name"] : latest_item
151
+ end
152
+ end
153
+
154
+ def latest_image
129
155
  @latest_image ||=
130
156
  begin
131
157
  items = cp.image_query["items"]
132
- matching_items = items.filter_map do |item|
133
- item["name"] if item["name"].start_with?("#{config.app}:")
134
- end
135
-
136
- # Or special string to indicate no image available
137
- if matching_items.empty?
138
- "#{config.app}:#{NO_IMAGE_AVAILABLE}"
139
- else
140
- matching_items.max_by { |item| extract_image_number(item) }
141
- end
158
+ latest_image_from(items)
142
159
  end
143
160
  end
144
161
 
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Command
4
+ class CleanupOldImages < Base
5
+ NAME = "cleanup-old-images"
6
+ OPTIONS = [
7
+ app_option(required: true),
8
+ skip_confirm_option
9
+ ].freeze
10
+ DESCRIPTION = "Deletes all images for an app that are older than the specified amount of days"
11
+ LONG_DESCRIPTION = <<~HEREDOC
12
+ - Deletes all images for an app that are older than the specified amount of days
13
+ - Specify the amount of days through `old_image_retention_days` in the `.controlplane/controlplane.yml` file
14
+ - Will ask for explicit user confirmation
15
+ - Does not affect the latest image, regardless of how old it is
16
+ HEREDOC
17
+
18
+ def call
19
+ return progress.puts "No old images found" if old_images.empty?
20
+
21
+ progress.puts "Old images:"
22
+ old_images.each do |image|
23
+ progress.puts " #{image[:name]} (#{thor_shell.set_color((image[:date]).to_s, :red)})"
24
+ end
25
+
26
+ return unless confirm_delete
27
+
28
+ progress.puts
29
+ delete_images
30
+ end
31
+
32
+ private
33
+
34
+ def old_images # rubocop:disable Metrics/MethodLength
35
+ @old_images ||=
36
+ begin
37
+ result_images = []
38
+
39
+ now = DateTime.now
40
+ old_image_retention_days = config[:old_image_retention_days]
41
+
42
+ images = cp.image_query["items"].filter { |item| item["name"].start_with?("#{config.app}:") }
43
+
44
+ # Remove latest image, because we don't want to delete the image that is currently deployed
45
+ latest_image_name = latest_image_from(images)
46
+ images = images.filter { |item| item["name"] != latest_image_name }
47
+
48
+ images.each do |image|
49
+ created_date = DateTime.parse(image["created"])
50
+ diff_in_days = (now - created_date).to_i
51
+ next unless diff_in_days >= old_image_retention_days
52
+
53
+ result_images.push({
54
+ name: image["name"],
55
+ date: created_date
56
+ })
57
+ end
58
+
59
+ result_images
60
+ end
61
+ end
62
+
63
+ def confirm_delete
64
+ return true if config.options[:yes]
65
+
66
+ thor_shell.yes?("\nAre you sure you want to delete these #{old_images.length} images (y/n)?")
67
+ end
68
+
69
+ def delete_images
70
+ old_images.each do |image|
71
+ cp.image_delete(image[:name])
72
+ progress.puts "#{image[:name]} deleted"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ module Command
6
+ class CleanupStaleApps < Base
7
+ NAME = "cleanup-stale-apps"
8
+ OPTIONS = [
9
+ app_option(required: true),
10
+ skip_confirm_option
11
+ ].freeze
12
+ DESCRIPTION = "Deletes the whole app (GVC with all workloads and all images) for all stale apps"
13
+ LONG_DESCRIPTION = <<~HEREDOC
14
+ - Deletes the whole app (GVC with all workloads and all images) for all stale apps
15
+ - Stale apps are identified based on the creation date of the latest image
16
+ - Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
17
+ - If `match_if_app_name_starts_with` is `true` in the `.controlplane/controlplane.yml` file, it will delete all stale apps that start with the name
18
+ - Will ask for explicit user confirmation
19
+ HEREDOC
20
+
21
+ def call # rubocop:disable Metrics/MethodLength
22
+ return progress.puts "No stale apps found" if stale_apps.empty?
23
+
24
+ progress.puts "Stale apps:"
25
+ stale_apps.each do |app|
26
+ progress.puts " #{app[:name]} (#{thor_shell.set_color((app[:date]).to_s, :red)})"
27
+ end
28
+
29
+ return unless confirm_delete
30
+
31
+ progress.puts
32
+ stale_apps.each do |app|
33
+ delete_gvc(app)
34
+ delete_images(app)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def stale_apps # rubocop:disable Metrics/MethodLength
41
+ @stale_apps ||=
42
+ begin
43
+ apps = []
44
+
45
+ now = DateTime.now
46
+ stale_app_image_deployed_days = config[:stale_app_image_deployed_days]
47
+
48
+ gvcs = cp.gvc_query(config.app)["items"]
49
+ gvcs.each do |gvc|
50
+ app_name = gvc["name"]
51
+
52
+ images = cp.image_query(app_name)["items"].filter { |item| item["name"].start_with?("#{app_name}:") }
53
+ image = latest_image_from(images, app_name: app_name, name_only: false)
54
+
55
+ created_date = DateTime.parse(image["created"])
56
+ diff_in_days = (now - created_date).to_i
57
+ next unless diff_in_days >= stale_app_image_deployed_days
58
+
59
+ apps.push({
60
+ name: app_name,
61
+ date: created_date,
62
+ images: images.map { |current_image| current_image["name"] }
63
+ })
64
+ end
65
+
66
+ apps
67
+ end
68
+ end
69
+
70
+ def confirm_delete
71
+ return true if config.options[:yes]
72
+
73
+ thor_shell.yes?("\nAre you sure you want to delete these #{stale_apps.length} apps (y/n)?")
74
+ end
75
+
76
+ def delete_gvc(app)
77
+ cp.gvc_delete(app[:name])
78
+ progress.puts "#{app[:name]} deleted"
79
+ end
80
+
81
+ def delete_images(app)
82
+ app[:images].each do |image|
83
+ cp.image_delete(image)
84
+ progress.puts "#{image} deleted"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -4,7 +4,8 @@ module Command
4
4
  class Delete < Base
5
5
  NAME = "delete"
6
6
  OPTIONS = [
7
- app_option(required: true)
7
+ app_option(required: true),
8
+ skip_confirm_option
8
9
  ].freeze
9
10
  DESCRIPTION = "Deletes the whole app (GVC with all workloads and all images)"
10
11
  LONG_DESCRIPTION = <<~HEREDOC
@@ -13,10 +14,7 @@ module Command
13
14
  HEREDOC
14
15
 
15
16
  def call
16
- progress.puts "Type 'delete' to delete #{config.app} and images"
17
- progress.print "> "
18
-
19
- return progress.puts "Not confirmed" unless $stdin.gets.chomp == "delete"
17
+ return unless confirm_delete
20
18
 
21
19
  delete_gvc
22
20
  delete_images
@@ -24,6 +22,16 @@ module Command
24
22
 
25
23
  private
26
24
 
25
+ def confirm_delete
26
+ return true if config.options[:yes]
27
+
28
+ confirmed = thor_shell.yes?("Are you sure you want to delete '#{config.app}' (y/n)?")
29
+ return false unless confirmed
30
+
31
+ progress.puts
32
+ true
33
+ end
34
+
27
35
  def delete_gvc
28
36
  progress.puts "- Deleting gvc:"
29
37
 
@@ -18,8 +18,8 @@ class Controlplane
18
18
  perform(cmd)
19
19
  end
20
20
 
21
- def image_query
22
- cmd = "cpln image query --org #{org} -o yaml --max -1 --prop repository=#{config.app}"
21
+ def image_query(app_name = config.app)
22
+ cmd = "cpln image query --org #{org} -o yaml --max -1 --prop repository=#{app_name}"
23
23
  perform_yaml(cmd)
24
24
  end
25
25
 
@@ -29,6 +29,15 @@ class Controlplane
29
29
 
30
30
  # gvc
31
31
 
32
+ def gvc_query(app_name = config.app)
33
+ # When `match_if_app_name_starts_with` is `true`, we query for any gvc containing the name,
34
+ # otherwise we query for a gvc with the exact name.
35
+ op = config.current[:match_if_app_name_starts_with] ? "~" : "="
36
+
37
+ cmd = "cpln gvc query --org #{org} -o yaml --prop name#{op}#{app_name}"
38
+ perform_yaml(cmd)
39
+ end
40
+
32
41
  def gvc_get(a_gvc = gvc)
33
42
  api.gvc_get(gvc: a_gvc, org: org)
34
43
  end
data/lib/cpl/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
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: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-19 00:00:00.000000000 Z
12
+ date: 2023-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: cgi
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - "~>"
19
- - !ruby/object:Gem::Version
20
- version: 0.3.6
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: 0.3.6
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: debug
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -53,48 +39,6 @@ dependencies:
53
39
  - - "~>"
54
40
  - !ruby/object:Gem::Version
55
41
  version: 2.8.1
56
- - !ruby/object:Gem::Dependency
57
- name: json
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: 2.6.3
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: 2.6.3
70
- - !ruby/object:Gem::Dependency
71
- name: net-http
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - "~>"
75
- - !ruby/object:Gem::Version
76
- version: 0.3.2
77
- type: :runtime
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - "~>"
82
- - !ruby/object:Gem::Version
83
- version: 0.3.2
84
- - !ruby/object:Gem::Dependency
85
- name: pathname
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "~>"
89
- - !ruby/object:Gem::Version
90
- version: 0.2.1
91
- type: :runtime
92
- prerelease: false
93
- version_requirements: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: 0.2.1
98
42
  - !ruby/object:Gem::Dependency
99
43
  name: psych
100
44
  requirement: !ruby/object:Gem::Requirement
@@ -109,20 +53,6 @@ dependencies:
109
53
  - - "~>"
110
54
  - !ruby/object:Gem::Version
111
55
  version: 5.1.0
112
- - !ruby/object:Gem::Dependency
113
- name: tempfile
114
- requirement: !ruby/object:Gem::Requirement
115
- requirements:
116
- - - "~>"
117
- - !ruby/object:Gem::Version
118
- version: 0.1.3
119
- type: :runtime
120
- prerelease: false
121
- version_requirements: !ruby/object:Gem::Requirement
122
- requirements:
123
- - - "~>"
124
- - !ruby/object:Gem::Version
125
- version: 0.1.3
126
56
  - !ruby/object:Gem::Dependency
127
57
  name: thor
128
58
  requirement: !ruby/object:Gem::Requirement
@@ -137,20 +67,6 @@ dependencies:
137
67
  - - "~>"
138
68
  - !ruby/object:Gem::Version
139
69
  version: 1.2.1
140
- - !ruby/object:Gem::Dependency
141
- name: yaml
142
- requirement: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - "~>"
145
- - !ruby/object:Gem::Version
146
- version: 0.2.1
147
- type: :runtime
148
- prerelease: false
149
- version_requirements: !ruby/object:Gem::Requirement
150
- requirements:
151
- - - "~>"
152
- - !ruby/object:Gem::Version
153
- version: 0.2.1
154
70
  - !ruby/object:Gem::Dependency
155
71
  name: rspec
156
72
  requirement: !ruby/object:Gem::Requirement
@@ -230,7 +146,8 @@ executables:
230
146
  extensions: []
231
147
  extra_rdoc_files: []
232
148
  files:
233
- - ".github/workflows/ci.yml"
149
+ - ".github/workflows/rspec.yml"
150
+ - ".github/workflows/rubocop.yml"
234
151
  - ".gitignore"
235
152
  - ".rspec"
236
153
  - ".rubocop.yml"
@@ -245,11 +162,15 @@ files:
245
162
  - cpl
246
163
  - cpl.gemspec
247
164
  - docs/commands.md
165
+ - docs/postgres.md
166
+ - docs/redis.md
248
167
  - docs/troubleshooting.md
249
168
  - examples/circleci.yml
250
169
  - examples/controlplane.yml
251
170
  - lib/command/base.rb
252
171
  - lib/command/build_image.rb
172
+ - lib/command/cleanup_old_images.rb
173
+ - lib/command/cleanup_stale_apps.rb
253
174
  - lib/command/config.rb
254
175
  - lib/command/delete.rb
255
176
  - lib/command/env.rb
@@ -275,8 +196,6 @@ files:
275
196
  - lib/cpl.rb
276
197
  - lib/cpl/version.rb
277
198
  - lib/main.rb
278
- - postgres.md
279
- - redis.md
280
199
  - script/generate_commands_docs
281
200
  - templates/gvc.yml
282
201
  - templates/identity.yml
File without changes
File without changes