renuo-cli 4.22.0 → 4.23.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/README.md +3 -2
- data/exe/renuo +5 -0
- data/lib/renuo/cli/commands/ci/check_deploio_status.rb +22 -10
- data/lib/renuo/cli/commands/ci/update_deploio_app.rb +1 -1
- data/lib/renuo/cli/commands/create_deploio_app.rb +2 -2
- data/lib/renuo/cli/commands/create_nine_cloudvm.rb +166 -0
- data/lib/renuo/cli/commands/setup_uptimerobot.rb +19 -9
- data/lib/renuo/cli/templates/semaphore/semaphore.yml.erb +2 -2
- data/lib/renuo/cli/version.rb +1 -1
- metadata +5 -5
- data/bin/renuo +0 -4
- data/lib/renuo/cli/commands/check_deploio_status.rb +0 -120
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d49d5760372b8bb7bd5ada89efeb64580a32f62997a701597a48a5ce7fda72ed
|
|
4
|
+
data.tar.gz: 384d94a32debe72aab7d4d68b0c3b4241ee4260e74caeaae63751daf8b044fba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e9a012730f76d8428624dbe15a56f78bab6b9c1f0109d30b1eebc0cd31434ebb1657d1704c4a5d887d6d4b8c1ec5157c1eb2dc0ab54f426a3a2f2d72317b90aa
|
|
7
|
+
data.tar.gz: cdf2265362bedb6f2172ca1058ccfdcf06f5823ea244a26aff46d1bf9bb68a537828cc4f571780eafdd41daeec3ae00e82b4d7f77869ed472233edaa5e30a9e8
|
data/README.md
CHANGED
|
@@ -30,7 +30,8 @@ After checking out the repo, run `bin/setup` to install dependencies.
|
|
|
30
30
|
|
|
31
31
|
Run `rake spec` to run the tests.
|
|
32
32
|
|
|
33
|
-
Run `
|
|
33
|
+
Run `bin/renuo` to run the executable against the working tree. (e.g. `bin/renuo -v`)
|
|
34
|
+
The shipped executable lives in `exe/renuo`; `bin/renuo` is a bundler binstub that loads it with the local code.
|
|
34
35
|
|
|
35
36
|
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
36
37
|
|
|
@@ -46,7 +47,7 @@ This binds the `renuo` command to your local version, so you can run commands di
|
|
|
46
47
|
|
|
47
48
|
```shell
|
|
48
49
|
renuo -h
|
|
49
|
-
renuo
|
|
50
|
+
renuo generate-password
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
data/exe/renuo
ADDED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
# :nocov:
|
|
4
4
|
module Renuo::Cli::Commands::Ci
|
|
5
|
-
class CheckDeploioStatus
|
|
5
|
+
class CheckDeploioStatus # rubocop:disable Metrics/ClassLength
|
|
6
6
|
TIMEOUT_IN_SECONDS = 600
|
|
7
7
|
INTERVAL_IN_SECONDS = 5
|
|
8
|
+
LOG_DRAIN_SECONDS = 2
|
|
8
9
|
|
|
9
10
|
command "ci check-deploio-status" do |c|
|
|
10
11
|
c.syntax = "renuo ci check-deploio-status [options] <app-name>"
|
|
@@ -17,11 +18,11 @@ module Renuo::Cli::Commands::Ci
|
|
|
17
18
|
|
|
18
19
|
def run
|
|
19
20
|
puts "(1/2) Checking build status for revision #{@revision}..."
|
|
20
|
-
poll "build"
|
|
21
|
+
with_streamed_logs("build") { poll "build" }
|
|
21
22
|
abort "build check timed out after #{TIMEOUT_IN_SECONDS} seconds" if build.nil?
|
|
22
23
|
|
|
23
24
|
puts "(2/2) Checking release status for build #{build_name}..."
|
|
24
|
-
poll "release"
|
|
25
|
+
with_streamed_logs("app") { poll "release" }
|
|
25
26
|
abort "release check timed out after #{TIMEOUT_IN_SECONDS} seconds" if release.nil?
|
|
26
27
|
end
|
|
27
28
|
|
|
@@ -49,12 +50,24 @@ module Renuo::Cli::Commands::Ci
|
|
|
49
50
|
Psych.load_stream stdout
|
|
50
51
|
end
|
|
51
52
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
def with_streamed_logs(type)
|
|
54
|
+
pid = Process.spawn(
|
|
55
|
+
"nctl logs application #{@app} -p #{@project} --type=#{type} -f --lines=100 --since 15m --no-labels",
|
|
56
|
+
out: $stdout, err: $stdout
|
|
57
|
+
)
|
|
58
|
+
yield
|
|
59
|
+
ensure
|
|
60
|
+
sleep LOG_DRAIN_SECONDS
|
|
61
|
+
stop_streaming(pid)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def stop_streaming(pid)
|
|
65
|
+
return unless pid
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
Process.kill("KILL", pid)
|
|
68
|
+
Process.wait(pid)
|
|
69
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
|
70
|
+
nil
|
|
58
71
|
end
|
|
59
72
|
|
|
60
73
|
def build
|
|
@@ -82,7 +95,7 @@ module Renuo::Cli::Commands::Ci
|
|
|
82
95
|
end
|
|
83
96
|
|
|
84
97
|
def succeeded?(status, type) # rubocop:disable Metrics/MethodLength
|
|
85
|
-
time =
|
|
98
|
+
time = Time.current.iso8601.to_s
|
|
86
99
|
|
|
87
100
|
case status
|
|
88
101
|
when "available", "success"
|
|
@@ -94,7 +107,6 @@ module Renuo::Cli::Commands::Ci
|
|
|
94
107
|
when "paused"
|
|
95
108
|
abort "#{time} app is paused"
|
|
96
109
|
when "error", "failed", "failure"
|
|
97
|
-
puts fetch_build_logs
|
|
98
110
|
abort "#{time} #{type} failed"
|
|
99
111
|
else
|
|
100
112
|
puts "#{time} #{type} status is #{status}, waiting..."
|
|
@@ -15,7 +15,7 @@ module Renuo::Cli::Commands::Ci
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def run
|
|
18
|
-
system! "nctl update app #{@app} -p #{@project}
|
|
18
|
+
system! "nctl update app #{@app} -p #{@project} " \
|
|
19
19
|
"#{"--build-env RUBY_VERSION=#{File.read(".ruby-version").strip} " if @docker}" \
|
|
20
20
|
"--git-revision #{@git_revision} --skip-repo-access-check"
|
|
21
21
|
end
|
|
@@ -96,11 +96,11 @@ class Renuo::Cli::Commands::CreateDeploioApp # rubocop:disable Metrics/ClassLeng
|
|
|
96
96
|
|
|
97
97
|
def set_postgres_version
|
|
98
98
|
loop do
|
|
99
|
-
@postgres_version = ask("Enter Postgres version (e.g.,
|
|
99
|
+
@postgres_version = ask("Enter Postgres version (e.g., 18) or leave empty to skip database creation: ")
|
|
100
100
|
break if @postgres_version.empty? || @postgres_version.match?(/^\d+$/)
|
|
101
101
|
|
|
102
102
|
say ">> The postgres version is invalid. Only major versions are allowed. " \
|
|
103
|
-
"For example, use
|
|
103
|
+
"For example, use 18 instead of 18.4. Please try again.".colorize(:red)
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../helpers/environments"
|
|
4
|
+
|
|
5
|
+
class Renuo::Cli::Commands::CreateNineCloudvm
|
|
6
|
+
SSH_KEY_FILE_NAME = "temporary_cloudvm_ssh_key"
|
|
7
|
+
SSH_ALGORITHM = "Ed25519"
|
|
8
|
+
DEFAULT_LOCATION = "nine-es34"
|
|
9
|
+
DEFAULT_MACHINE_TYPE = "nine-small-1"
|
|
10
|
+
DEFAULT_OS = "debian13"
|
|
11
|
+
VPS_SETUP_GUIDE_REPO = "https://github.com/renuo/vps-setup-guide"
|
|
12
|
+
|
|
13
|
+
command "create-nine-cloudvm" do |c|
|
|
14
|
+
c.syntax = "renuo create-nine-cloudvm [project-name]"
|
|
15
|
+
c.summary = "Generates the script necessary to setup a cloud VM on Nine."
|
|
16
|
+
c.description = <<~DESC
|
|
17
|
+
Generates the script necessary to setup a cloud VM on Nine.
|
|
18
|
+
This command will:
|
|
19
|
+
- Prompt for the organization, project name, location, machine type, OS, and 1Password vault name.
|
|
20
|
+
- Validate the provided inputs.
|
|
21
|
+
- Generate an SSH key (stored in 1Password) to access the cloud VM.
|
|
22
|
+
- Generate the commands to create a cloud VM for each environment on Nine.
|
|
23
|
+
DESC
|
|
24
|
+
c.option "-o", "--org <organization>", String, "The organization name"
|
|
25
|
+
c.example "renuo create-nine-cloudvm my-app",
|
|
26
|
+
"Prompts the user for the necessary information and generates the commands " \
|
|
27
|
+
"to create the cloud VMs on Nine."
|
|
28
|
+
c.action { |args, options| new.run(args, options) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run(args, options = {})
|
|
32
|
+
@project_name, = args
|
|
33
|
+
@options = options
|
|
34
|
+
parse_arguments
|
|
35
|
+
setup_ssh_key
|
|
36
|
+
setup_environments
|
|
37
|
+
say_configuration_note
|
|
38
|
+
ensure
|
|
39
|
+
cleanup
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def valid_name?(name)
|
|
45
|
+
name&.length&.between?(3, 63) && name.match?(/^[a-z0-9-]+$/)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def parse_arguments
|
|
49
|
+
set_organization
|
|
50
|
+
set_project_name
|
|
51
|
+
set_location
|
|
52
|
+
set_machine_type
|
|
53
|
+
set_os
|
|
54
|
+
set_vault_name
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def set_project_name
|
|
58
|
+
loop do
|
|
59
|
+
break if valid_name?(@project_name)
|
|
60
|
+
|
|
61
|
+
say ">> Project name must be between 3 and 63 characters and can only contain lowercase letters, " \
|
|
62
|
+
"numbers, and hyphens. Please try again.".colorize(:red)
|
|
63
|
+
|
|
64
|
+
@project_name = ask("Enter the project name (e.g: my-app): ")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
@project_name_with_org_prefix = "#{@organization}-#{@project_name}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def set_organization
|
|
71
|
+
@organization = @options.org if @options.org
|
|
72
|
+
|
|
73
|
+
loop do
|
|
74
|
+
break if valid_name?(@organization)
|
|
75
|
+
|
|
76
|
+
say ">> Organization name must be between 3 and 63 characters and can only contain lowercase letters, " \
|
|
77
|
+
"numbers, and hyphens. Please try again.".colorize(:red)
|
|
78
|
+
|
|
79
|
+
@organization = ask("Enter the organization name (default: renuo): ") { |q| q.default = "renuo" }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def set_location
|
|
84
|
+
@location = ask("Enter the location (default: #{DEFAULT_LOCATION}): ") { |q| q.default = DEFAULT_LOCATION }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def set_machine_type
|
|
88
|
+
@machine_type = ask("Enter the machine type (default: #{DEFAULT_MACHINE_TYPE}): ") do |q|
|
|
89
|
+
q.default = DEFAULT_MACHINE_TYPE
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def set_os
|
|
94
|
+
@os = ask("Enter the operating system (default: #{DEFAULT_OS}): ") { |q| q.default = DEFAULT_OS }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def set_vault_name
|
|
98
|
+
@vault_name = ask("An SSH key to access the cloud VM will be stored on 1Password. " \
|
|
99
|
+
"Enter the 1Password vault name: ") do |q|
|
|
100
|
+
q.default = "Deploio"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def setup_ssh_key
|
|
105
|
+
say "\n# Generate the SSH key to access the cloud VM\n".bold
|
|
106
|
+
generate_ssh_key(SSH_KEY_FILE_NAME)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def setup_environments
|
|
110
|
+
ENVIRONMENTS.each do |environment|
|
|
111
|
+
say "\n# Commands to create #{environment} cloud VM \n".bold
|
|
112
|
+
say_cloudvm_creation(environment)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def say_configuration_note
|
|
117
|
+
say "\n# Configure the cloud VMs\n".bold
|
|
118
|
+
say <<~OUTPUT
|
|
119
|
+
Once the cloud VMs are up, configure them (SSH access, monitoring, backups) with the
|
|
120
|
+
Ansible VPS setup guide: #{VPS_SETUP_GUIDE_REPO}
|
|
121
|
+
OUTPUT
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def cleanup
|
|
125
|
+
say "\n# Cleanup temporary files\n".bold
|
|
126
|
+
say "rm #{SSH_KEY_FILE_NAME} #{SSH_KEY_FILE_NAME}.pub"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def say_cloudvm_creation(environment)
|
|
130
|
+
say <<~OUTPUT
|
|
131
|
+
nctl create cloudvm #{environment} \\
|
|
132
|
+
--project #{@project_name_with_org_prefix} \\
|
|
133
|
+
--wait \\
|
|
134
|
+
--location="#{@location}" \\
|
|
135
|
+
--machine-type="#{@machine_type}" \\
|
|
136
|
+
--hostname="#{hostname(environment)}" \\
|
|
137
|
+
--os="#{@os}" \\
|
|
138
|
+
--ssh-keys-from-files=#{SSH_KEY_FILE_NAME}.pub
|
|
139
|
+
OUTPUT
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def hostname(environment)
|
|
143
|
+
"#{@project_name_with_org_prefix}-#{environment}"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def generate_ssh_key(file_name)
|
|
147
|
+
say <<~OUTPUT
|
|
148
|
+
# Create SSH key item in 1Password directly
|
|
149
|
+
op item create \\
|
|
150
|
+
--account renuo.1password.com \\
|
|
151
|
+
--category ssh \\
|
|
152
|
+
--ssh-generate-key #{SSH_ALGORITHM.downcase} \\
|
|
153
|
+
--title "#{@project_name_with_org_prefix}-cloudvm-key" \\
|
|
154
|
+
--vault #{@vault_name} \\
|
|
155
|
+
--tags #{@project_name_with_org_prefix}
|
|
156
|
+
|
|
157
|
+
# Extract keys to temp files for cloud VM usage
|
|
158
|
+
op item get "#{@project_name_with_org_prefix}-cloudvm-key" --vault #{@vault_name} \\
|
|
159
|
+
--account renuo.1password.com \\
|
|
160
|
+
--reveal --fields "public key" > #{file_name}.pub
|
|
161
|
+
op item get "#{@project_name_with_org_prefix}-cloudvm-key" --vault #{@vault_name} --reveal \\
|
|
162
|
+
--account renuo.1password.com \\
|
|
163
|
+
--fields "private key" --format json | jq -r '.ssh_formats.openssh.value' > #{file_name}
|
|
164
|
+
OUTPUT
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Renuo::Cli::Commands::SetupUptimerobot
|
|
4
|
-
CONTACT_GROUP_IDS = "2811620_0_0-6298845_0_0-5223624_0_0"
|
|
5
|
-
HTTPS_MONITORING = 1
|
|
6
|
-
STATUS_PAUSED = 0
|
|
7
|
-
|
|
8
4
|
command "setup-uptimerobot" do |c|
|
|
9
5
|
c.syntax = "renuo setup-uptimerobot"
|
|
10
6
|
c.summary = "Sets up uptimerobot for the given project"
|
|
@@ -17,8 +13,8 @@ class Renuo::Cli::Commands::SetupUptimerobot
|
|
|
17
13
|
|
|
18
14
|
def initialize(args)
|
|
19
15
|
abort("No project name given.") if args.nil?
|
|
20
|
-
@api_key = ask_for_api_key
|
|
21
16
|
@url = validate_url(args)
|
|
17
|
+
@api_key = read_api_key
|
|
22
18
|
end
|
|
23
19
|
|
|
24
20
|
def run
|
|
@@ -30,10 +26,18 @@ class Renuo::Cli::Commands::SetupUptimerobot
|
|
|
30
26
|
|
|
31
27
|
private
|
|
32
28
|
|
|
33
|
-
|
|
29
|
+
LIST_API_KEY_CMD = "op item list --tags renuo-cli-uptimerobot-api-key --format=json"
|
|
30
|
+
EXTRACT_API_KEY_CMD = "op item get --reveal --field credential"
|
|
31
|
+
def read_api_key
|
|
34
32
|
say "This command will configure uptimerobot for your project."
|
|
35
|
-
say "
|
|
36
|
-
|
|
33
|
+
say "Fetching the uptimerobot api_key from 1Password..."
|
|
34
|
+
stdout, stderr, status = Open3.capture3("#{LIST_API_KEY_CMD} | #{EXTRACT_API_KEY_CMD}")
|
|
35
|
+
abort("Failed to fetch the uptimerobot api_key from 1Password: #{stderr.strip}") unless status.success?
|
|
36
|
+
|
|
37
|
+
api_key = stdout.strip
|
|
38
|
+
abort("No 1Password item tagged 'renuo-cli-uptimerobot-api-key' was found.") if api_key.empty?
|
|
39
|
+
|
|
40
|
+
api_key
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
def validate_url(args)
|
|
@@ -42,13 +46,19 @@ class Renuo::Cli::Commands::SetupUptimerobot
|
|
|
42
46
|
URI.parse(args.first)
|
|
43
47
|
end
|
|
44
48
|
|
|
49
|
+
HTTPS_MONITORING = 1
|
|
50
|
+
STATUS_PAUSED = 0
|
|
51
|
+
DOMAIN_EXPIRY_NOTIFICATIONS_DISABLED = 1
|
|
52
|
+
# Format is "id_threshold_recurrence": notify #uptime after 10 minutes of downtime, without re-notifying.
|
|
53
|
+
ALERT_CONTACTS = "7783511_10_0"
|
|
45
54
|
def create_robot_params
|
|
46
55
|
{
|
|
47
56
|
friendly_name: @url.host.downcase,
|
|
48
57
|
url: @url.to_s,
|
|
49
58
|
type: HTTPS_MONITORING,
|
|
50
59
|
interval: 300,
|
|
51
|
-
alert_contacts:
|
|
60
|
+
alert_contacts: ALERT_CONTACTS,
|
|
61
|
+
disable_domain_expire_notifications: DOMAIN_EXPIRY_NOTIFICATIONS_DISABLED
|
|
52
62
|
}
|
|
53
63
|
end
|
|
54
64
|
|
|
@@ -24,7 +24,7 @@ global_job_config:
|
|
|
24
24
|
- source .semaphore/bin/cache_restore rails
|
|
25
25
|
- bundle config set deployment 'true'
|
|
26
26
|
- bundle config set path 'vendor/bundle'
|
|
27
|
-
- bundle install
|
|
27
|
+
- bundle install --retry 3
|
|
28
28
|
|
|
29
29
|
blocks:
|
|
30
30
|
- name: linting
|
|
@@ -49,7 +49,7 @@ blocks:
|
|
|
49
49
|
value: test
|
|
50
50
|
prologue:
|
|
51
51
|
commands:
|
|
52
|
-
- sem-service start postgres
|
|
52
|
+
- sem-service start postgres 18
|
|
53
53
|
- cp .env.example .env
|
|
54
54
|
- bundle exec rails db:create db:schema:load
|
|
55
55
|
jobs:
|
data/lib/renuo/cli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: renuo-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Renuo AG
|
|
8
|
-
bindir:
|
|
8
|
+
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
@@ -62,9 +62,8 @@ extra_rdoc_files: []
|
|
|
62
62
|
files:
|
|
63
63
|
- LICENSE.txt
|
|
64
64
|
- README.md
|
|
65
|
-
-
|
|
65
|
+
- exe/renuo
|
|
66
66
|
- lib/renuo/cli.rb
|
|
67
|
-
- lib/renuo/cli/commands/check_deploio_status.rb
|
|
68
67
|
- lib/renuo/cli/commands/ci/check_deploio_status.rb
|
|
69
68
|
- lib/renuo/cli/commands/ci/setup.rb
|
|
70
69
|
- lib/renuo/cli/commands/ci/update_deploio_app.rb
|
|
@@ -77,6 +76,7 @@ files:
|
|
|
77
76
|
- lib/renuo/cli/commands/create_deploio_object_storage.rb
|
|
78
77
|
- lib/renuo/cli/commands/create_heroku_app.rb
|
|
79
78
|
- lib/renuo/cli/commands/create_new_logins.rb
|
|
79
|
+
- lib/renuo/cli/commands/create_nine_cloudvm.rb
|
|
80
80
|
- lib/renuo/cli/commands/create_pr.rb
|
|
81
81
|
- lib/renuo/cli/commands/create_slidev_presentation.rb
|
|
82
82
|
- lib/renuo/cli/commands/debug.rb
|
|
@@ -132,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
132
|
- !ruby/object:Gem::Version
|
|
133
133
|
version: '0'
|
|
134
134
|
requirements: []
|
|
135
|
-
rubygems_version: 4.0.
|
|
135
|
+
rubygems_version: 4.0.15
|
|
136
136
|
specification_version: 4
|
|
137
137
|
summary: The Renuo CLI automates some common workflows.
|
|
138
138
|
test_files: []
|
data/bin/renuo
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# :nocov:
|
|
4
|
-
class Renuo::Cli::Commands::CheckDeploioStatus
|
|
5
|
-
TIMEOUT_IN_SECONDS = 600
|
|
6
|
-
INTERVAL_IN_SECONDS = 5
|
|
7
|
-
|
|
8
|
-
command "check-deploio-status" do |c|
|
|
9
|
-
c.syntax = "renuo check-deploio-status"
|
|
10
|
-
c.summary = "DEPRECATED: Use 'renuo ci check-deploio-status' instead."
|
|
11
|
-
c.description = "Checks the build and release status of the deployment."
|
|
12
|
-
c.option "-a", "--app <name>", String, "The name of the app"
|
|
13
|
-
c.option "-p", "--project <name>", String, "The name of the project"
|
|
14
|
-
c.option "-g", "--git-revision <revision>", String, "The git revision to check"
|
|
15
|
-
c.action { |_, options| new(options).run }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def initialize(options)
|
|
19
|
-
@revision = options.git_revision || `git rev-parse HEAD`.strip
|
|
20
|
-
@app = options.app || ENV.fetch("DEPLOIO_APP_NAME", nil)
|
|
21
|
-
@project = options.project || ENV.fetch("DEPLOIO_PROJECT", nil)
|
|
22
|
-
|
|
23
|
-
abort "missing app name" if @app.nil?
|
|
24
|
-
abort "missing project name" if @project.nil?
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def run
|
|
28
|
-
warn "DEPRECATED: Use 'renuo ci check-deploio-status' instead."
|
|
29
|
-
puts "(1/2) Checking build status for revision #{@revision}..."
|
|
30
|
-
poll "build"
|
|
31
|
-
abort "build check timed out after #{TIMEOUT_IN_SECONDS} seconds" if build.nil?
|
|
32
|
-
|
|
33
|
-
puts "(2/2) Checking release status for build #{build_name}..."
|
|
34
|
-
poll "release"
|
|
35
|
-
abort "release check timed out after #{TIMEOUT_IN_SECONDS} seconds" if release.nil?
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def system!(cmd)
|
|
41
|
-
abort unless system cmd
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def fetch(type)
|
|
45
|
-
command = "nctl get #{type} -a #{@app} -p #{@project} -o yaml"
|
|
46
|
-
stdout, stderr, status = Open3.capture3 command
|
|
47
|
-
|
|
48
|
-
abort "error fetching #{type} information: #{stderr}" unless status.success?
|
|
49
|
-
Psych.load_stream stdout
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def fetch_build_logs
|
|
53
|
-
command = "nctl logs build -a #{@app} -p #{@project} -l 5000 --no-labels"
|
|
54
|
-
stdout, stderr, status = Open3.capture3 command
|
|
55
|
-
|
|
56
|
-
puts "error fetching build logs: #{stderr}" unless status.success?
|
|
57
|
-
stdout
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def build
|
|
61
|
-
@build ||= fetch("builds").find do |build|
|
|
62
|
-
build.dig("spec", "forProvider", "sourceConfig", "git", "revision") == @revision
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def build_name
|
|
67
|
-
@build_name ||= build.dig("metadata", "name")
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def build_status
|
|
71
|
-
build.dig("status", "atProvider", "buildStatus")
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def release
|
|
75
|
-
@release ||= fetch("releases").find do |release|
|
|
76
|
-
release.dig("spec", "forProvider", "build", "name") == build_name
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def release_status
|
|
81
|
-
release.dig("status", "atProvider", "releaseStatus")
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def succeeded?(status, type) # rubocop:disable Metrics/MethodLength
|
|
85
|
-
time = "[#{Time.now.utc.iso8601}]"
|
|
86
|
-
|
|
87
|
-
case status
|
|
88
|
-
when "available", "success"
|
|
89
|
-
puts "#{time} #{type} succeeded"
|
|
90
|
-
true
|
|
91
|
-
when "superseded"
|
|
92
|
-
puts "#{time} release was superseded"
|
|
93
|
-
true
|
|
94
|
-
when "paused"
|
|
95
|
-
abort "#{time} app is paused"
|
|
96
|
-
when "error", "failed", "failure"
|
|
97
|
-
puts fetch_build_logs
|
|
98
|
-
abort "#{time} #{type} failed"
|
|
99
|
-
else
|
|
100
|
-
puts "#{time} #{type} status is #{status}, waiting..."
|
|
101
|
-
instance_variable_set :"@#{type}", nil
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def poll(type)
|
|
106
|
-
elapsed = 0
|
|
107
|
-
|
|
108
|
-
while elapsed < TIMEOUT_IN_SECONDS
|
|
109
|
-
if send type
|
|
110
|
-
break if succeeded?(send(:"#{type}_status"), type)
|
|
111
|
-
else
|
|
112
|
-
puts "no matching #{type} found, waiting..."
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
sleep INTERVAL_IN_SECONDS
|
|
116
|
-
elapsed += INTERVAL_IN_SECONDS
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
# :nocov:
|