minfra-cli 0.1.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 +7 -0
- data/.dockerignore +12 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +2 -0
- data/Dockerfile +12 -0
- data/bin/build +20 -0
- data/bin/console +16 -0
- data/bin/container_exec +9 -0
- data/bin/run_tests +74 -0
- data/bin/setup.sh +22 -0
- data/exe/minfra +6 -0
- data/lib/deep_merge.rb +149 -0
- data/lib/hash.rb +28 -0
- data/lib/minfra/cli/ask.rb +43 -0
- data/lib/minfra/cli/command.rb +35 -0
- data/lib/minfra/cli/commands/dev.rb +54 -0
- data/lib/minfra/cli/commands/kube.rb +279 -0
- data/lib/minfra/cli/commands/project/branch.rb +17 -0
- data/lib/minfra/cli/commands/project/tag.rb +40 -0
- data/lib/minfra/cli/commands/project.rb +113 -0
- data/lib/minfra/cli/commands/setup.rb +49 -0
- data/lib/minfra/cli/commands/stack/app_template.rb +65 -0
- data/lib/minfra/cli/commands/stack/client_template.rb +36 -0
- data/lib/minfra/cli/commands/stack/kube_stack_template.rb +94 -0
- data/lib/minfra/cli/commands/stack.rb +120 -0
- data/lib/minfra/cli/commands/tag.rb +86 -0
- data/lib/minfra/cli/common.rb +41 -0
- data/lib/minfra/cli/config.rb +111 -0
- data/lib/minfra/cli/document.rb +19 -0
- data/lib/minfra/cli/hook.rb +65 -0
- data/lib/minfra/cli/logging.rb +26 -0
- data/lib/minfra/cli/main_command.rb +32 -0
- data/lib/minfra/cli/plugins.rb +34 -0
- data/lib/minfra/cli/runner.rb +59 -0
- data/lib/minfra/cli/templater.rb +63 -0
- data/lib/minfra/cli/version.rb +5 -0
- data/lib/minfra/cli.rb +80 -0
- data/lib/orchparty/ast.rb +53 -0
- data/lib/orchparty/cli.rb +69 -0
- data/lib/orchparty/context.rb +22 -0
- data/lib/orchparty/dsl_parser.rb +229 -0
- data/lib/orchparty/dsl_parser_kubernetes.rb +361 -0
- data/lib/orchparty/kubernetes_application.rb +305 -0
- data/lib/orchparty/plugin.rb +24 -0
- data/lib/orchparty/plugins/env.rb +41 -0
- data/lib/orchparty/transformations/all.rb +18 -0
- data/lib/orchparty/transformations/mixin.rb +73 -0
- data/lib/orchparty/transformations/remove_internal.rb +16 -0
- data/lib/orchparty/transformations/sort.rb +10 -0
- data/lib/orchparty/transformations/variable.rb +56 -0
- data/lib/orchparty/transformations.rb +24 -0
- data/lib/orchparty/version.rb +3 -0
- data/lib/orchparty.rb +59 -0
- data/minfra-cli.gemspec +40 -0
- data/project.json +7 -0
- data/templates/kind.yaml.erb +33 -0
- data/templates/kube_config.yaml.erb +7 -0
- data/templates/minfra_config.json.erb +26 -0
- metadata +196 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require_relative 'stack/app_template'
|
3
|
+
require_relative 'stack/client_template'
|
4
|
+
require_relative 'stack/kube_stack_template'
|
5
|
+
|
6
|
+
module Minfra
|
7
|
+
module Cli
|
8
|
+
class Stack < Command
|
9
|
+
|
10
|
+
desc "describe","get information about a stack"
|
11
|
+
option :environment, aliases: ['-e']
|
12
|
+
def describe
|
13
|
+
pp @minfra_config.describe(options["environment"])
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "dashboard <stack_name>", "openening a dashboard for a stack"
|
17
|
+
option :environment, aliases: ['-e']
|
18
|
+
option :deployment, aliases: ['-d']
|
19
|
+
option :cluster, aliases: ['-c']
|
20
|
+
def dashboard(stack_name='all')
|
21
|
+
kube.dashboard(stack_name, options[:environment], options[:deployment], options[:cluster])
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "deploy <stack_name> '<message> (optional)'", "deploy a complete stack"
|
25
|
+
option :environment, aliases: ['-e']
|
26
|
+
# option :deployment, aliases: ['-d']
|
27
|
+
option :cluster, aliases: ['-c']
|
28
|
+
option :dev, type: :boolean # currently, about to be changed
|
29
|
+
option :explain, type: :boolean
|
30
|
+
option :install, type: :boolean
|
31
|
+
option :test, type: :boolean
|
32
|
+
option :opts
|
33
|
+
def deploy(stack_name, message='')
|
34
|
+
kube.deploy(stack_name, message)
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "rollback <extraargs>", "rollback a deployment"
|
38
|
+
option :environment, aliases: ['-e']
|
39
|
+
option :deployment, aliases: ['-d']
|
40
|
+
option :cluster, aliases: ['-c']
|
41
|
+
def rollback(*args)
|
42
|
+
STDERR.puts "needs implementation"
|
43
|
+
exit 1
|
44
|
+
#kube.rollback(stack_name, options[:environment], options[:deployment], options[:cluster], args)
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "destroy", "remove the whole stack"
|
48
|
+
option :environment, aliases: ['-e']
|
49
|
+
option :cluster, aliases: ['-c']
|
50
|
+
def destroy(stack_name)
|
51
|
+
kube.destroy(stack_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "list", "list all stacks in an environment"
|
55
|
+
option :environment, aliases: ['-e']
|
56
|
+
option :cluster, aliases: ['-c']
|
57
|
+
def list
|
58
|
+
kube.list
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "app", "show the app a stack provides"
|
62
|
+
option :environment, aliases: ['-e']
|
63
|
+
def app(stack_name)
|
64
|
+
cluster=nil
|
65
|
+
deployment=nil
|
66
|
+
template = Minfra::Cli::StackM::AppTemplate.new(stack_name, minfra_config)
|
67
|
+
template.read
|
68
|
+
puts "Template: #{template.app_path}\n#{template.to_s}"
|
69
|
+
apps = AppResource.all(filter: {identifier: template.app.identifier} ).data
|
70
|
+
if apps.empty?
|
71
|
+
puts "Auth: app uninstalled"
|
72
|
+
atts = {
|
73
|
+
identifier: template.app.identifier,
|
74
|
+
name: template.app.name,
|
75
|
+
short_name: template.app.short_name,
|
76
|
+
description: template.app.description,
|
77
|
+
native: template.app.native,
|
78
|
+
start_url: template.app.start_url,
|
79
|
+
public: template.app.public
|
80
|
+
}
|
81
|
+
app_res=AppResource.build( {data: {attributes: atts, type: 'apps'}} )
|
82
|
+
app_res.save
|
83
|
+
app = app_res.data
|
84
|
+
else
|
85
|
+
app = apps.first
|
86
|
+
end
|
87
|
+
puts "Auth: app installed #{app.id}"
|
88
|
+
|
89
|
+
clients = OauthClientResource.all(filter: {app_id: app.id}).data
|
90
|
+
if clients.empty?
|
91
|
+
puts "Auth: client not registered"
|
92
|
+
atts= {redirect_uris: template.client.redirect_uris.map { |r| "#{app.start_url}#{r}" },
|
93
|
+
native: template.client.native, ppid: template.client.ppid, name: template.client.name, app_id: app.id}
|
94
|
+
client_res=OauthClientResource.build( {data: {attributes: atts, type: 'oauth_clients'}} )
|
95
|
+
client_res.save
|
96
|
+
client=client_res.data
|
97
|
+
else
|
98
|
+
client = clients.first
|
99
|
+
end
|
100
|
+
puts "Auth: client registered #{client.id}"
|
101
|
+
|
102
|
+
client_template=Minfra::Cli::StackM::ClientTemplate.new(stack_name, client.name, minfra_config)
|
103
|
+
unless client_template.exist?
|
104
|
+
File.write(client_template.path.to_s, { name: client.name, identifier: client.identifier, secret: client.secret }.to_json)
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
# TODO: create app configuration
|
109
|
+
# TODO: create provider
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def kube
|
114
|
+
Kube.new(options, @minfra_config)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Minfra::Cli.register("stack", "dealing wit stacks", Minfra::Cli::Stack)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Minfra
|
4
|
+
module Cli
|
5
|
+
class Tag
|
6
|
+
include Minfra::Cli::Logging
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@now = Time.now.utc
|
10
|
+
@format = '%Y_%m_%dT%H_%M_%SZ'
|
11
|
+
@tags_folder = '.tags'
|
12
|
+
end
|
13
|
+
|
14
|
+
def tag_current_commit_for_deploy(message, format)
|
15
|
+
@format = format if format
|
16
|
+
|
17
|
+
info 'Creating tag.'
|
18
|
+
debug "Using .tags folder..."
|
19
|
+
write_tag_folder_file(message)
|
20
|
+
run_cmd(cmd_add_tag_info("#{@tags_folder}/#{tag_name}"), :system)
|
21
|
+
run_cmd(cmd_create_tag_commit, :system)
|
22
|
+
run_cmd(cmd_tag_commit(message), :system)
|
23
|
+
info 'Pushing tag to remote.'
|
24
|
+
run_cmd(cmd_push, :system)
|
25
|
+
run_cmd(cmd_push_tag, :system)
|
26
|
+
end
|
27
|
+
|
28
|
+
def ensure_commit_is_pushed
|
29
|
+
info 'Checking that the current commit is present on the remote.'
|
30
|
+
output = run_cmd(cmd_ensure_commit_is_pushed)
|
31
|
+
|
32
|
+
if output.empty?
|
33
|
+
exit_error "The current commit is not present on the remote.\n" \
|
34
|
+
'Please push your changes to origin and try again.'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def cmd_ensure_commit_is_pushed
|
39
|
+
'git branch -r --contains $(git rev-list --max-count=1 HEAD)'
|
40
|
+
end
|
41
|
+
|
42
|
+
def cmd_add_tag_info(file)
|
43
|
+
"git add #{file}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def cmd_create_tag_commit
|
47
|
+
"git commit -m '#{tag_name}'"
|
48
|
+
end
|
49
|
+
|
50
|
+
def cmd_tag_commit(message)
|
51
|
+
"git tag -a #{tag_name} -m '#{message}'"
|
52
|
+
end
|
53
|
+
|
54
|
+
def cmd_push
|
55
|
+
"git push"
|
56
|
+
end
|
57
|
+
|
58
|
+
def cmd_push_tag
|
59
|
+
"git push origin #{tag_name}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def git_current_branch
|
63
|
+
`git rev-parse --abbrev-ref HEAD`.strip
|
64
|
+
end
|
65
|
+
|
66
|
+
#TBD: this should be more flexible
|
67
|
+
def tag_name
|
68
|
+
"#{git_current_branch}-REL-#{@now.strftime(@format)}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def write_tag_folder_file(message)
|
72
|
+
File.write("#{@tags_folder}/#{tag_name}", "#{message}\n")
|
73
|
+
end
|
74
|
+
|
75
|
+
def write_tag_file(_message)
|
76
|
+
File.write(@tags_file.to_s, "#{tag_name}\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
def run_cmd(cmd, _how = :system)
|
80
|
+
Runner.run(cmd)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#Minfra::Cli.register("tag", "creating tags", Minfra::Cli::Tag)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Minfra
|
4
|
+
module Cli
|
5
|
+
module Common
|
6
|
+
|
7
|
+
def exit_error(msg)
|
8
|
+
STDERR.puts("ERROR: #{msg}" )
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_cmd(cmd, type = :non_system, silence: false)
|
13
|
+
puts cmd unless silence
|
14
|
+
case type
|
15
|
+
when :exec
|
16
|
+
Kernel.exec(cmd)
|
17
|
+
when :bash
|
18
|
+
res = system(%{bash -c "#{Array.new(cmd).join(' && ')}"})
|
19
|
+
exit_error("failed!") unless res
|
20
|
+
nil # no output!
|
21
|
+
when :system
|
22
|
+
res = system(cmd)
|
23
|
+
exit_error("failed!") unless res
|
24
|
+
nil # no output!
|
25
|
+
else
|
26
|
+
`#{cmd}` # with output!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_cmd(cmd, silence: false)
|
31
|
+
reply = JSON.parse(run_cmd(cmd, silence: silence))
|
32
|
+
rescue JSON::ParserError, TypeError
|
33
|
+
error "ERROR: #{$ERROR_INFO.message}"
|
34
|
+
error reply
|
35
|
+
error "command was: #{cmd}"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'hashie/mash'
|
3
|
+
require 'json'
|
4
|
+
require_relative 'templater'
|
5
|
+
module Minfra
|
6
|
+
module Cli
|
7
|
+
# responsible the read the config file(s) and add a small abstraction layer on top of it
|
8
|
+
class Config
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
class ConfigNotFoundError < StandardError
|
12
|
+
end
|
13
|
+
class EnvironmentNotFoundError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :base_path
|
17
|
+
attr_reader :config_path
|
18
|
+
attr_reader :stacks_path
|
19
|
+
attr_reader :me_path
|
20
|
+
attr_reader :kube_path
|
21
|
+
attr_reader :kube_config_path
|
22
|
+
attr_reader :kind_config_path
|
23
|
+
|
24
|
+
attr_reader :orch_env
|
25
|
+
attr_reader :orch_env_config
|
26
|
+
attr_reader :config
|
27
|
+
attr_reader :project
|
28
|
+
|
29
|
+
def self.load(orch_env, base_path_str = nil)
|
30
|
+
new(base_path_str).load(orch_env)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(base_path_str=nil)
|
34
|
+
init!(base_path_str)
|
35
|
+
end
|
36
|
+
|
37
|
+
def init!(base_path_str=nil)
|
38
|
+
debug( "Config: initializing" )
|
39
|
+
@base_path = Pathname.new(base_path_str || ENV["MINFRA_PATH"]).expand_path
|
40
|
+
@me_path = @base_path.join('me')
|
41
|
+
@project_config_path=@base_path.join("config","project.json")
|
42
|
+
@config_path = @me_path.join('config.json')
|
43
|
+
@stacks_path = @base_path.join('stacks')
|
44
|
+
@kube_path=@me_path.join('kube')
|
45
|
+
@kube_config_path=@kube_path.join('config')
|
46
|
+
@kind_config_path=@me_path.join("kind.yaml.erb")
|
47
|
+
@project_minfrarc_path = @base_path.join("config",'minfrarc.rb')
|
48
|
+
require @project_minfrarc_path if @project_minfrarc_path.exist?
|
49
|
+
@me_minfrarc_path = @me_path.join('minfrarc.rb')
|
50
|
+
require @me_minfrarc_path if @me_minfrarc_path.exist?
|
51
|
+
if config_path.exist?
|
52
|
+
@config = Hashie::Mash.new(JSON.parse(Minfra::Cli::Templater.render(File.read(config_path),{})))
|
53
|
+
else
|
54
|
+
warn("personal minfra configuration file '#{config_path}' not found, you might have to run 'minfra setup dev'")
|
55
|
+
@config = Hashie::Mash.new({})
|
56
|
+
end
|
57
|
+
@project = Hashie::Mash.new(JSON.parse(Minfra::Cli::Templater.render(File.read(@project_config_path),{})))
|
58
|
+
end
|
59
|
+
|
60
|
+
def load(orch_env)
|
61
|
+
debug( "loading config env: #{orch_env} #{@orch_env}" )
|
62
|
+
return self if defined?(@orch_env)
|
63
|
+
@orch_env = orch_env
|
64
|
+
@orch_env_config = @config.environments[@orch_env] || raise(EnvironmentNotFoundError.new("Configuration for orchestration environment '#{@orch_env}' not found. Available orechstration environments: #{@config.environments.keys.inspect}"))
|
65
|
+
@project= @project.
|
66
|
+
deep_merge(@project.environments[@orch_env]).
|
67
|
+
deep_merge(@config).
|
68
|
+
deep_merge(@orch_env_config)
|
69
|
+
@orch_env_config['env']=@orch_env
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def name
|
74
|
+
@project.name
|
75
|
+
end
|
76
|
+
|
77
|
+
def describe(environment)
|
78
|
+
{
|
79
|
+
env: {
|
80
|
+
minfra_name: ENV["MINFRA_NAME"],
|
81
|
+
minfra_path: ENV["MINFRA_PATH"],
|
82
|
+
},
|
83
|
+
base_path: base_path.to_s,
|
84
|
+
me_path: me_path.to_s,
|
85
|
+
kube_path: kube_path.to_s,
|
86
|
+
config_path: config_path.to_s,
|
87
|
+
config: @config.to_h,
|
88
|
+
env_config: @orch_env_config.to_h,
|
89
|
+
project: @project
|
90
|
+
}
|
91
|
+
end
|
92
|
+
def dev?
|
93
|
+
@orch_env=='dev'
|
94
|
+
end
|
95
|
+
|
96
|
+
def email
|
97
|
+
@config.identity.email
|
98
|
+
end
|
99
|
+
|
100
|
+
def api_key
|
101
|
+
@project.account_api_key
|
102
|
+
end
|
103
|
+
|
104
|
+
def endpoint(name)
|
105
|
+
Hashie::Mash.new({"api_key": api_key}).deep_merge(@project.endpoints[name])
|
106
|
+
rescue
|
107
|
+
raise("endpoint #{name} is undefinded please add <env>:endpoints:#{name} to you #{config_path} file ")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Minfra
|
2
|
+
module Cli
|
3
|
+
class Document
|
4
|
+
def self.document(config, message)
|
5
|
+
new(config).document(message)
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def document(message)
|
13
|
+
return true if @config.dev?
|
14
|
+
puts "TBD: calling documentation hooks"
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# no support for around hooks yet
|
2
|
+
|
3
|
+
module Minfra
|
4
|
+
module Cli
|
5
|
+
module Hook
|
6
|
+
class Hook
|
7
|
+
def initialize(type, name, block)
|
8
|
+
@type=type
|
9
|
+
@name=name
|
10
|
+
@block=block
|
11
|
+
end
|
12
|
+
|
13
|
+
def match?(type, name)
|
14
|
+
@type == type && @name == name
|
15
|
+
end
|
16
|
+
|
17
|
+
def exec (obj)
|
18
|
+
obj.instance_eval(&@block)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class Hooker
|
24
|
+
def initialize(klass)
|
25
|
+
@klass=klass
|
26
|
+
@hooks=[]
|
27
|
+
end
|
28
|
+
|
29
|
+
def register_before(name, block)
|
30
|
+
@hooks << Hook.new(:before, name, block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def register_after(name, block)
|
34
|
+
@hooks << Hook.new(:after, name, block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(obj, name, &block)
|
38
|
+
@hooks.select do |h| h.match?(:before, name) end.each do |h| h.exec(obj) end
|
39
|
+
obj.instance_eval(&block)
|
40
|
+
@hooks.select do |h| h.match?(:after, name) end.each do |h| h.exec(obj) end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.included(klass)
|
45
|
+
klass.extend(ClassMethods)
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
def hooks
|
50
|
+
@hooker||=Hooker.new(self)
|
51
|
+
end
|
52
|
+
def after_hook(name,&block)
|
53
|
+
hooks.register_after(name, block)
|
54
|
+
end
|
55
|
+
def before_hook(name, &block)
|
56
|
+
hooks.register_before(name, block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def with_hook(hook_name, &block)
|
61
|
+
self.class.hooks.call(self, hook_name, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Minfra
|
2
|
+
module Cli
|
3
|
+
module Logging
|
4
|
+
def error(str)
|
5
|
+
STDERR.puts "Error: #{str}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def exit_error(str)
|
9
|
+
error str
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def info(str)
|
14
|
+
STDOUT.puts str
|
15
|
+
end
|
16
|
+
|
17
|
+
def debug(str)
|
18
|
+
STDOUT.puts "Debug: #{str}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def deprecated(comment)
|
22
|
+
puts "DEPRECATED: #{comment}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Minfra
|
2
|
+
module Cli
|
3
|
+
class Main < Command
|
4
|
+
|
5
|
+
desc 'kube', 'kubectl wrapper and other features'
|
6
|
+
long_desc '
|
7
|
+
'
|
8
|
+
option :environment, required: false, aliases: ['-e']
|
9
|
+
option :cluster
|
10
|
+
def kube(*args)
|
11
|
+
kube.kubectl_command(args)
|
12
|
+
end
|
13
|
+
|
14
|
+
# tbd: move this to project
|
15
|
+
desc 'tag', 'tag current commit for deployment - triggers CI'
|
16
|
+
option :message, default: 'release', aliases: ['-m']
|
17
|
+
option :format, required: false, aliases: ['-f']
|
18
|
+
def tag
|
19
|
+
Tag.new.tag_current_commit_for_deploy(options[:message], options[:format])
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'version', 'prints version of the cli'
|
23
|
+
def version
|
24
|
+
puts Minfra::Cli::VERSION
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.exit_on_failure?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Minfra
|
2
|
+
module Cli
|
3
|
+
class Plugins
|
4
|
+
def self.load
|
5
|
+
[Pathname.new(ENV["MINFRA_PATH"]).join("config","minfra_plugins.json"),
|
6
|
+
Pathname.new(ENV["MINFRA_PATH"]).join("me","minfra_plugins.json")].each do |file|
|
7
|
+
|
8
|
+
next unless File.exist?(file)
|
9
|
+
|
10
|
+
plugins=JSON.parse(File.read(file))
|
11
|
+
plugins["plugins"].each do |spec|
|
12
|
+
opts=spec["opts"] || {}
|
13
|
+
opts.merge(require: false)
|
14
|
+
if opts["path"]
|
15
|
+
begin
|
16
|
+
$LOAD_PATH.unshift opts["path"]+"/lib"
|
17
|
+
require spec["name"]
|
18
|
+
rescue Gem::Requirement::BadRequirementError
|
19
|
+
STDERR.puts("Can't load plugin: #{spec["name"]}")
|
20
|
+
end
|
21
|
+
else
|
22
|
+
begin
|
23
|
+
Gem::Specification.find_by_name(spec["name"])
|
24
|
+
gem spec["name"], spec["version"]
|
25
|
+
rescue Gem::MissingSpecError
|
26
|
+
STDERR.puts("Can't load plugin: #{spec["name"]}, #{spec["version"]}; run 'minfra plugin setup'")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Minfra
|
4
|
+
module Cli
|
5
|
+
class Runner
|
6
|
+
class Result
|
7
|
+
attr_reader :stdout, :stderr
|
8
|
+
def initialize(stdout,stderr, status)
|
9
|
+
@stderr=stderr
|
10
|
+
@stdout=stdout
|
11
|
+
@status=status
|
12
|
+
end
|
13
|
+
|
14
|
+
def success?
|
15
|
+
@status.success?
|
16
|
+
end
|
17
|
+
|
18
|
+
def error?
|
19
|
+
!success?
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
@stdout.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
include Logging
|
28
|
+
def self.run(cmd, **args)
|
29
|
+
new(cmd, **args).run
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :exit_on_error
|
33
|
+
def initialize(cmd, exit_on_error: true)
|
34
|
+
@cmd=cmd
|
35
|
+
@exit_on_error = exit_on_error
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
debug(@cmd)
|
40
|
+
res=nil
|
41
|
+
begin
|
42
|
+
res=Result.new(*Open3.capture3(@cmd))
|
43
|
+
rescue
|
44
|
+
end
|
45
|
+
if res&.error?
|
46
|
+
STDERR.puts "command failed: #{@cmd}"
|
47
|
+
STDERR.puts res.stdout
|
48
|
+
STDERR.puts res.stderr
|
49
|
+
end
|
50
|
+
if exit_on_error && res&.error?
|
51
|
+
STDERR.puts "exiting on error"
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
res
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Minfra
|
4
|
+
module Cli
|
5
|
+
class Templater # not threadsafe!
|
6
|
+
def self.read(path, params: {}, fallback: nil)
|
7
|
+
p=Pathname.new(path)
|
8
|
+
if p.exist?
|
9
|
+
content=File.read(path)
|
10
|
+
else
|
11
|
+
if fallback
|
12
|
+
content=fallback
|
13
|
+
else
|
14
|
+
raise "file #{path} not found"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
render(template, params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.render(template, params)
|
21
|
+
new(template).render(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(template)
|
25
|
+
@erb = ERB.new(template)
|
26
|
+
@check_mode=false
|
27
|
+
@check_missing=[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def missing?
|
31
|
+
!check_missing.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_missing(&block)
|
35
|
+
begin
|
36
|
+
@check_mode = true
|
37
|
+
@check_block = block
|
38
|
+
@check_missing = []
|
39
|
+
@erb.result(binding)
|
40
|
+
ensure
|
41
|
+
@check_block = nil
|
42
|
+
@check_mode = false
|
43
|
+
end
|
44
|
+
@check_missing
|
45
|
+
end
|
46
|
+
|
47
|
+
def render(params)
|
48
|
+
@erb.result_with_hash(params)
|
49
|
+
end
|
50
|
+
|
51
|
+
def method_missing(name)
|
52
|
+
if @check_mode
|
53
|
+
if @check_block
|
54
|
+
@check_block.call(name)
|
55
|
+
end
|
56
|
+
@check_missing << name
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|