ops_team 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +20 -0
- data/bin/ops +8 -0
- data/bin/tag +16 -0
- data/etc/ops.template.yml +11 -0
- data/etc/ruby.template.yml +29 -0
- data/etc/terraform.template.yml +26 -0
- data/lib/action.rb +18 -0
- data/lib/builtin.rb +12 -0
- data/lib/builtins/down.rb +46 -0
- data/lib/builtins/env.rb +18 -0
- data/lib/builtins/helpers/dependency_handler.rb +33 -0
- data/lib/builtins/init.rb +51 -0
- data/lib/builtins/up.rb +47 -0
- data/lib/dependencies/apk.rb +26 -0
- data/lib/dependencies/apt.rb +24 -0
- data/lib/dependencies/brew.rb +24 -0
- data/lib/dependencies/cask.rb +15 -0
- data/lib/dependencies/custom.rb +21 -0
- data/lib/dependencies/docker.rb +19 -0
- data/lib/dependencies/gem.rb +27 -0
- data/lib/dependencies/terraform.rb +23 -0
- data/lib/dependency.rb +59 -0
- data/lib/ops.rb +96 -0
- data/lib/options.rb +13 -0
- data/lib/output.rb +63 -0
- data/loader.rb +4 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fa5c498bf634206ab5ef4e53313731fb1ab8ee71456051d03f0b50d7b98f71ab
|
4
|
+
data.tar.gz: 6167a9ec3c12915fe62f3ccc3de1ce2a7f22351d32a7b2c10d8bb2b3c6da291d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0273b1834ceb76c119328e45574ba27a924bb9ba50334661ad78ffebee8883f6efa0de75f8a97536d351103e36c64accd29ac1ae68892085828600b1c85de2fb
|
7
|
+
data.tar.gz: f021f9ea483736c3e13692d58f9284c105117fac4b1b873dd8918b9e5b123b4bd900c8b4735805a1b7f5f149c4ff8fb5c9a5f5efafb5e75644c1c3e9ebbf5001
|
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
6
|
+
|
7
|
+
gem "colorize"
|
8
|
+
gem "require_all"
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
gem "fuubar"
|
12
|
+
gem "rspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem "pry"
|
17
|
+
gem "pry-byebug"
|
18
|
+
gem "rerun"
|
19
|
+
gem "rubocop"
|
20
|
+
end
|
data/bin/ops
ADDED
data/bin/tag
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# tags a commit, asking for input when needed
|
3
|
+
|
4
|
+
if [ -n "$1" ]; then
|
5
|
+
tag="$1"
|
6
|
+
else
|
7
|
+
tag=$(grep -o "'[0-9.]*'" ops_team.gemspec | sed "s/'//g")
|
8
|
+
if [ -z "$tag" ]; then
|
9
|
+
read -p "Enter tag value: " tag
|
10
|
+
fi
|
11
|
+
fi
|
12
|
+
|
13
|
+
comment="Tagging $tag for release"
|
14
|
+
echo "Tagging '$tag' with comment '$comment'..."
|
15
|
+
git tag -a "$tag" -m "$comment"
|
16
|
+
git push origin "$tag"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
dependencies:
|
2
|
+
gem:
|
3
|
+
- bundler
|
4
|
+
- rerun
|
5
|
+
custom:
|
6
|
+
- bundle
|
7
|
+
actions:
|
8
|
+
start:
|
9
|
+
command: echo update me
|
10
|
+
stop:
|
11
|
+
command: echo update me too
|
12
|
+
test:
|
13
|
+
command: rspec
|
14
|
+
alias: t
|
15
|
+
test-watch:
|
16
|
+
command: rerun -x ops test
|
17
|
+
alias: tw
|
18
|
+
lint:
|
19
|
+
command: bundle exec rubocop --safe-auto-correct
|
20
|
+
alias: l
|
21
|
+
build:
|
22
|
+
command: gem build *.gemspec
|
23
|
+
alias: b
|
24
|
+
install:
|
25
|
+
command: gem install `ls -t *.gem | head -n1`
|
26
|
+
alias: i
|
27
|
+
build-and-install:
|
28
|
+
command: ops build && ops install
|
29
|
+
alias: bi
|
@@ -0,0 +1,26 @@
|
|
1
|
+
dependencies:
|
2
|
+
brew:
|
3
|
+
- terraform
|
4
|
+
apt:
|
5
|
+
- terraform
|
6
|
+
custom:
|
7
|
+
- terraform init
|
8
|
+
actions:
|
9
|
+
apply:
|
10
|
+
command: terraform apply
|
11
|
+
alias: a
|
12
|
+
apply-auto-approve:
|
13
|
+
command: terraform apply --auto-approve
|
14
|
+
alias: aa
|
15
|
+
destroy:
|
16
|
+
command: terraform destroy
|
17
|
+
alias: d
|
18
|
+
destroy-auto-approve:
|
19
|
+
command: terraform destroy --auto-approve
|
20
|
+
alias: dd
|
21
|
+
plan:
|
22
|
+
command: terraform plan
|
23
|
+
alias: p
|
24
|
+
graph:
|
25
|
+
command: terraform graph
|
26
|
+
alias: g
|
data/lib/action.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# represents one action to be performed in the shell
|
4
|
+
# can assemble a command line from a command and args
|
5
|
+
class Action
|
6
|
+
def initialize(command, args)
|
7
|
+
@command = command
|
8
|
+
@args = args
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
Kernel.exec(to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{@command} #{@args.join(' ')}"
|
17
|
+
end
|
18
|
+
end
|
data/lib/builtin.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'require_all'
|
4
|
+
require_rel "../dependencies"
|
5
|
+
|
6
|
+
require 'builtin'
|
7
|
+
require 'builtins/helpers/dependency_handler'
|
8
|
+
|
9
|
+
module Builtins
|
10
|
+
class Down < Builtin
|
11
|
+
def run
|
12
|
+
# TODO: return a success/failure status to the caller
|
13
|
+
unmeet_dependencies
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def dependency_handler
|
19
|
+
Helpers::DependencyHandler.new(@config["dependencies"])
|
20
|
+
end
|
21
|
+
|
22
|
+
def unmeet_dependencies
|
23
|
+
dependency_handler.dependencies.each do |dependency|
|
24
|
+
# don't even output anything for dependencies that shouldn't be considered on this machine
|
25
|
+
next unless dependency.should_meet?
|
26
|
+
|
27
|
+
Output.status("[#{dependency.type}] #{dependency.name}")
|
28
|
+
|
29
|
+
unmeet_dependency(dependency)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def unmeet_dependency(dependency)
|
34
|
+
# TODO: make this simpler, and factor in `should_meet?` above, too
|
35
|
+
dependency.unmeet if dependency.met? || dependency.always_act?
|
36
|
+
|
37
|
+
if dependency.success?
|
38
|
+
Output.okay
|
39
|
+
else
|
40
|
+
Output.failed
|
41
|
+
Output.error("Error unmeeting #{dependency.type} dependency '#{dependency.name}':")
|
42
|
+
puts(dependency.output)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/builtins/env.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'builtin'
|
4
|
+
require 'output'
|
5
|
+
|
6
|
+
module Builtins
|
7
|
+
class Env < Builtin
|
8
|
+
def run
|
9
|
+
Output.print(environment)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def environment
|
15
|
+
ENV['environment'] || 'dev'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'builtin'
|
4
|
+
require 'output'
|
5
|
+
|
6
|
+
require 'require_all'
|
7
|
+
require_rel "../../dependencies"
|
8
|
+
|
9
|
+
module Builtins
|
10
|
+
module Helpers
|
11
|
+
class DependencyHandler
|
12
|
+
def initialize(dependency_set)
|
13
|
+
@dependency_set = dependency_set
|
14
|
+
end
|
15
|
+
|
16
|
+
def dependencies
|
17
|
+
return [] unless @dependency_set
|
18
|
+
|
19
|
+
@dependency_set.map do |type, names|
|
20
|
+
dependencies_for(type, names)
|
21
|
+
end.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
def dependencies_for(type, names)
|
25
|
+
dependency_class = Dependencies.const_get(type.capitalize.to_sym)
|
26
|
+
|
27
|
+
names.map { |name| dependency_class.new(name) }
|
28
|
+
rescue NameError
|
29
|
+
Output.error("No way to handle dependencies of type '#{type}'; ignoring.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
require 'builtin'
|
6
|
+
require 'output'
|
7
|
+
|
8
|
+
module Builtins
|
9
|
+
class Init < Builtin
|
10
|
+
OPS_YML = "ops.yml"
|
11
|
+
TEMPLATE_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "etc"))
|
12
|
+
OPS_YML_TEMPLATE = File.join(TEMPLATE_DIR, "%<template_name>s.template.yml")
|
13
|
+
DEFAULT_TEMPLATE_NAME = "ops"
|
14
|
+
|
15
|
+
def run
|
16
|
+
if File.exist?(OPS_YML)
|
17
|
+
Output.error("File '#{OPS_YML} exists; not initializing.")
|
18
|
+
else
|
19
|
+
Output.out("Creating '#{OPS_YML} from template...")
|
20
|
+
FileUtils.cp(template_path, OPS_YML)
|
21
|
+
end
|
22
|
+
rescue SystemCallError
|
23
|
+
Output.error(template_not_found_message)
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def template_name_arg
|
30
|
+
@args[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def template_path
|
34
|
+
format(OPS_YML_TEMPLATE, template_name: template_name_arg || DEFAULT_TEMPLATE_NAME)
|
35
|
+
end
|
36
|
+
|
37
|
+
def template_name_list
|
38
|
+
@template_name_list ||= Dir.entries(TEMPLATE_DIR).map do |name|
|
39
|
+
name.match(/^([^.]*).template.yml/)&.captures&.first
|
40
|
+
end.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def template_not_found_message
|
44
|
+
<<~MESSAGE
|
45
|
+
Template '#{template_path} does not exist.
|
46
|
+
\nValid template names are:
|
47
|
+
- #{template_name_list.join("\n - ")}\n
|
48
|
+
MESSAGE
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/builtins/up.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'require_all'
|
4
|
+
require_rel "../dependencies"
|
5
|
+
|
6
|
+
require 'builtin'
|
7
|
+
require 'builtins/helpers/dependency_handler'
|
8
|
+
require 'output'
|
9
|
+
|
10
|
+
module Builtins
|
11
|
+
class Up < Builtin
|
12
|
+
def run
|
13
|
+
# TODO: return a success/failure status to the caller
|
14
|
+
meet_dependencies
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def dependency_handler
|
20
|
+
Helpers::DependencyHandler.new(@config["dependencies"])
|
21
|
+
end
|
22
|
+
|
23
|
+
def meet_dependencies
|
24
|
+
dependency_handler.dependencies.each do |dependency|
|
25
|
+
# don't even output anything for dependencies that shouldn't be considered on this machine
|
26
|
+
next unless dependency.should_meet?
|
27
|
+
|
28
|
+
Output.status("[#{dependency.type}] #{dependency.name}")
|
29
|
+
|
30
|
+
meet_dependency(dependency)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def meet_dependency(dependency)
|
35
|
+
# TODO: make this simpler, and factor in `should_meet?` above, too
|
36
|
+
dependency.meet if !dependency.met? || dependency.always_act?
|
37
|
+
|
38
|
+
if dependency.success?
|
39
|
+
Output.okay
|
40
|
+
else
|
41
|
+
Output.failed
|
42
|
+
Output.error("Error meeting #{dependency.type} dependency '#{dependency.name}':")
|
43
|
+
puts(dependency.output)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
require 'dependency'
|
6
|
+
|
7
|
+
module Dependencies
|
8
|
+
class Apk < Dependency
|
9
|
+
def met?
|
10
|
+
execute("apk info | grep -q #{name}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def meet
|
14
|
+
execute("apk add #{name}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def unmeet
|
18
|
+
# do nothing; we don't want to uninstall packages and reinstall them every time
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def should_meet?
|
23
|
+
system("which apk")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
|
5
|
+
module Dependencies
|
6
|
+
class Apt < Dependency
|
7
|
+
def met?
|
8
|
+
execute("dpkg-query --show --showformat '${db:Status-Status}\n' #{name} | grep -q ^installed")
|
9
|
+
end
|
10
|
+
|
11
|
+
def meet
|
12
|
+
execute("apt-get install -y #{name}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmeet
|
16
|
+
# do nothing; we don't want to uninstall packages and reinstall them every time
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def should_meet?
|
21
|
+
`uname`.chomp == "Linux"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
|
5
|
+
module Dependencies
|
6
|
+
class Brew < Dependency
|
7
|
+
def met?
|
8
|
+
execute("brew list #{name}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def meet
|
12
|
+
execute("brew install #{name}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmeet
|
16
|
+
# do nothing; we don't want to uninstall packages and reinstall them every time
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def should_meet?
|
21
|
+
`uname`.chomp == "Darwin"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
|
5
|
+
module Dependencies
|
6
|
+
class Custom < Dependency
|
7
|
+
def met?
|
8
|
+
# we always want to try to meet this dependency
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def meet
|
13
|
+
# this dependency is just a custom, idempotent command
|
14
|
+
execute(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def unmeet
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
|
5
|
+
module Dependencies
|
6
|
+
class Docker < Dependency
|
7
|
+
def met?
|
8
|
+
execute("cd #{name} && docker-compose ps | grep -q ' Up '")
|
9
|
+
end
|
10
|
+
|
11
|
+
def meet
|
12
|
+
execute("cd #{name} && docker-compose up -d")
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmeet
|
16
|
+
execute("cd #{name} && docker-compose down")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
require 'options'
|
5
|
+
|
6
|
+
module Dependencies
|
7
|
+
class Gem < Dependency
|
8
|
+
def met?
|
9
|
+
execute("gem list -i '^#{name}$'")
|
10
|
+
end
|
11
|
+
|
12
|
+
def meet
|
13
|
+
if Options.get("gem.use_sudo")
|
14
|
+
execute("sudo gem install #{name}")
|
15
|
+
elsif Options.get("gem.user_install")
|
16
|
+
execute("gem install --user-install #{name}")
|
17
|
+
else
|
18
|
+
execute("gem install #{name}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def unmeet
|
23
|
+
# do nothing; we don't want to uninstall packages and reinstall them every time
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dependency'
|
4
|
+
|
5
|
+
module Dependencies
|
6
|
+
class Terraform < Dependency
|
7
|
+
def met?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def always_act?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def meet
|
16
|
+
execute("cd #{name} && terraform init && terraform apply -input=false --auto-approve")
|
17
|
+
end
|
18
|
+
|
19
|
+
def unmeet
|
20
|
+
execute("cd #{name} && terraform destroy -input=false --auto-approve")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/dependency.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'English'
|
5
|
+
|
6
|
+
require 'output'
|
7
|
+
|
8
|
+
class Dependency
|
9
|
+
DESCRIPTION_TYPE_WIDTH = 8
|
10
|
+
|
11
|
+
attr_reader :name, :output, :exit_code
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def met?
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def meet
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def unmeet
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
# should_meet? can be used to implement dependencies that should only be met on some platforms,
|
30
|
+
# e.g. brew on Macs and apt on Linux
|
31
|
+
# it can be used to base a decision on anything else that can be read from the environment at
|
32
|
+
# runtime
|
33
|
+
def should_meet?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
# if true, this type of resource must always have `meet` and `unmeet` called;
|
38
|
+
# useful for resources that can't easily be checked to see if they're met
|
39
|
+
def always_act?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
def type
|
44
|
+
self.class.name.split('::').last
|
45
|
+
end
|
46
|
+
|
47
|
+
def success?
|
48
|
+
@exit_code.nil? ? true : @exit_code.zero?
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def execute(cmd)
|
54
|
+
@output, status = Open3.capture2e(cmd)
|
55
|
+
@exit_code = status.exitstatus
|
56
|
+
|
57
|
+
success?
|
58
|
+
end
|
59
|
+
end
|
data/lib/ops.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'require_all'
|
6
|
+
|
7
|
+
require 'action'
|
8
|
+
require 'output'
|
9
|
+
require 'options'
|
10
|
+
require_rel "builtins"
|
11
|
+
|
12
|
+
# executes commands defined in local `ops.yml`
|
13
|
+
class Ops
|
14
|
+
class UnknownActionError < StandardError; end
|
15
|
+
|
16
|
+
CONFIG_FILE = "ops.yml"
|
17
|
+
|
18
|
+
INVALID_SYNTAX_EXIT_CODE = 1
|
19
|
+
|
20
|
+
def initialize(argv)
|
21
|
+
@action_name = argv[0]
|
22
|
+
@args = argv[1..-1]
|
23
|
+
|
24
|
+
Options.set(config["options"] || {})
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
exit(INVALID_SYNTAX_EXIT_CODE) unless syntax_valid?
|
29
|
+
|
30
|
+
return builtin.run if builtin
|
31
|
+
|
32
|
+
Output.warn("Running '#{action}' from #{CONFIG_FILE}...")
|
33
|
+
action.run
|
34
|
+
rescue UnknownActionError => e
|
35
|
+
Output.error("Error: #{e}")
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def syntax_valid?
|
41
|
+
if @action_name.nil?
|
42
|
+
# TODO: output to stderr
|
43
|
+
puts "Usage: ops <action>"
|
44
|
+
false
|
45
|
+
else
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def builtin
|
51
|
+
@builtin ||= Builtins.const_get(builtin_class_name).new(@args, config)
|
52
|
+
rescue NameError
|
53
|
+
# this means there isn't a builtin with that name in that module
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def builtin_class_name
|
58
|
+
@action_name.capitalize.to_sym
|
59
|
+
end
|
60
|
+
|
61
|
+
def action
|
62
|
+
@action ||= Action.new(command, @args)
|
63
|
+
end
|
64
|
+
|
65
|
+
def command
|
66
|
+
@command ||= begin
|
67
|
+
return actions[@action_name]["command"] if actions[@action_name]
|
68
|
+
return aliases[@action_name]["command"] if aliases[@action_name]
|
69
|
+
|
70
|
+
raise UnknownActionError, "Unknown action: #{@action_name}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def actions
|
75
|
+
config["actions"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def config
|
79
|
+
@config ||= begin
|
80
|
+
Output.warn("File '#{CONFIG_FILE}' does not exist.") unless File.exist?(CONFIG_FILE)
|
81
|
+
YAML.load_file(CONFIG_FILE)
|
82
|
+
rescue StandardError
|
83
|
+
{}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def aliases
|
88
|
+
@aliases ||= begin
|
89
|
+
actions.each_with_object({}) do |(_name, body), alias_hash|
|
90
|
+
alias_hash[body["alias"]] = body if body.include?("alias")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
Ops.new(ARGV).run if $PROGRAM_NAME == __FILE__
|
data/lib/options.rb
ADDED
data/lib/output.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'colorize'
|
4
|
+
|
5
|
+
class Output
|
6
|
+
@out = STDOUT
|
7
|
+
@err = STDERR
|
8
|
+
|
9
|
+
STATUS_WIDTH = "50"
|
10
|
+
|
11
|
+
OKAY = "OK"
|
12
|
+
SKIPPED = "SKIPPED"
|
13
|
+
FAILED = "FAILED"
|
14
|
+
|
15
|
+
# used to silence output, e.g. in testing
|
16
|
+
class DummyOutput
|
17
|
+
def print(*_); end
|
18
|
+
|
19
|
+
def puts(*_); end
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def status(name)
|
24
|
+
@out.print(format("%-#{STATUS_WIDTH}<name>s ", name: name))
|
25
|
+
end
|
26
|
+
|
27
|
+
def okay
|
28
|
+
@out.puts(OKAY.green)
|
29
|
+
end
|
30
|
+
|
31
|
+
def skipped
|
32
|
+
@out.puts(SKIPPED.yellow)
|
33
|
+
end
|
34
|
+
|
35
|
+
def failed
|
36
|
+
@out.puts(FAILED.red)
|
37
|
+
end
|
38
|
+
|
39
|
+
def warn(msg)
|
40
|
+
@err.puts(msg.yellow)
|
41
|
+
end
|
42
|
+
|
43
|
+
def error(msg)
|
44
|
+
@err.puts(msg.red)
|
45
|
+
end
|
46
|
+
|
47
|
+
def out(msg)
|
48
|
+
@out.puts(msg)
|
49
|
+
end
|
50
|
+
|
51
|
+
def print(msg)
|
52
|
+
@out.print(msg)
|
53
|
+
end
|
54
|
+
|
55
|
+
def silence
|
56
|
+
@out = @err = dummy_output
|
57
|
+
end
|
58
|
+
|
59
|
+
def dummy_output
|
60
|
+
@dummy_output ||= DummyOutput.new
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/loader.rb
ADDED
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ops_team
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nickthecook@gmail.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.8.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: require_all
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.1.6
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.1.6
|
53
|
+
description:
|
54
|
+
email:
|
55
|
+
executables:
|
56
|
+
- ops
|
57
|
+
extensions: []
|
58
|
+
extra_rdoc_files: []
|
59
|
+
files:
|
60
|
+
- Gemfile
|
61
|
+
- bin/ops
|
62
|
+
- bin/tag
|
63
|
+
- etc/ops.template.yml
|
64
|
+
- etc/ruby.template.yml
|
65
|
+
- etc/terraform.template.yml
|
66
|
+
- lib/action.rb
|
67
|
+
- lib/builtin.rb
|
68
|
+
- lib/builtins/down.rb
|
69
|
+
- lib/builtins/env.rb
|
70
|
+
- lib/builtins/helpers/dependency_handler.rb
|
71
|
+
- lib/builtins/init.rb
|
72
|
+
- lib/builtins/up.rb
|
73
|
+
- lib/dependencies/apk.rb
|
74
|
+
- lib/dependencies/apt.rb
|
75
|
+
- lib/dependencies/brew.rb
|
76
|
+
- lib/dependencies/cask.rb
|
77
|
+
- lib/dependencies/custom.rb
|
78
|
+
- lib/dependencies/docker.rb
|
79
|
+
- lib/dependencies/gem.rb
|
80
|
+
- lib/dependencies/terraform.rb
|
81
|
+
- lib/dependency.rb
|
82
|
+
- lib/ops.rb
|
83
|
+
- lib/options.rb
|
84
|
+
- lib/output.rb
|
85
|
+
- loader.rb
|
86
|
+
homepage:
|
87
|
+
licenses:
|
88
|
+
- GPL-3.0-only
|
89
|
+
metadata: {}
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubygems_version: 3.0.3
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: ops_team handles basic operations tasks for your project, driven by YAML
|
109
|
+
config
|
110
|
+
test_files: []
|