ops_team 0.1.7 → 0.2.4

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: af22f3dad0669e5cae68bc2bfbe6f8c2e7227bc11d74a4295d59c9e7fa4ea79e
4
- data.tar.gz: bed9b0448b2b2051d6e2d817f7f48bab44c1b901d5586b157d81491bdd0dd2a2
3
+ metadata.gz: fb200091bd81044096f650bc1647958dd129b12b14c309516b7e7ce0324e8889
4
+ data.tar.gz: 0edf7442cd2106ac2de48b6c14d16510111fa10759fe320aaea1856f366c8703
5
5
  SHA512:
6
- metadata.gz: f46ef6fb3cdc4fb430405b73d7f1c9c0f0261fe313d7ff02275b2ea1a31be6c3283cb3c232fd601af34c852ba3ae3eb4ceb00f7db2253a519d92ca8e01413a55
7
- data.tar.gz: 1462ee358b52b81e48526bb276723eb2f9fce3e16d8ee72089182544606c2e8501d045af0505e10a09e6527317ebd729eaa71042bebbc533521ae379f2a92f13
6
+ metadata.gz: '0379eecf548037718aebf63b722f9571f21410daafd13a6b9ae893cfe7d3fbd3c0a58c40ea10dd1ac35d52c1de580894a774859755185dd8c32eb130db6d31fc'
7
+ data.tar.gz: 6e08799eb7cf0c196c88e93ecd68f7d48beedd803291d07b362750c9d738785736e9db49ca3c02d180544efa731f7064d5b5537016db8427b826e8057e4a2210
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ echo $KEY1
4
+ echo $KEY2
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ echo "$SECRET1"
4
+ echo "$SECRET2"
@@ -7,5 +7,7 @@ dependencies:
7
7
  actions:
8
8
  start:
9
9
  command: docker-compose up -d
10
+ description: starts the service
10
11
  stop:
11
12
  command: docker-compose down
13
+ description: stops the service
@@ -7,23 +7,31 @@ dependencies:
7
7
  actions:
8
8
  start:
9
9
  command: echo update me
10
+ description: starts the app
10
11
  stop:
11
12
  command: echo update me too
13
+ description: stops the app
12
14
  test:
13
15
  command: rspec
14
16
  alias: t
17
+ description: runs unit tests
15
18
  test-watch:
16
19
  command: rerun -x ops test
17
20
  alias: tw
21
+ description: runs unit tests every time a file changes
18
22
  lint:
19
23
  command: bundle exec rubocop --safe-auto-correct
20
24
  alias: l
25
+ description: runs rubocop with safe autocorrect
21
26
  build:
22
27
  command: gem build *.gemspec
23
28
  alias: b
29
+ description: builds the gem
24
30
  install:
25
31
  command: gem install `ls -t *.gem | head -n1`
26
32
  alias: i
33
+ description: installs the gem
27
34
  build-and-install:
28
35
  command: ops build && ops install
29
36
  alias: bi
37
+ description: builds and installs the gem
@@ -9,21 +9,28 @@ actions:
9
9
  apply:
10
10
  command: terraform apply
11
11
  alias: a
12
+ description: runs 'terraform apply'
12
13
  apply-auto-approve:
13
14
  command: terraform apply --auto-approve
14
15
  alias: aa
16
+ description: runs 'terraform apply' with auto-approve
15
17
  destroy:
16
18
  command: terraform destroy
17
19
  alias: d
20
+ description: runs 'terraform destroy'
18
21
  destroy-auto-approve:
19
22
  command: terraform destroy --auto-approve
20
23
  alias: dd
24
+ description: runs 'terraform destroy' with auto-approve
21
25
  plan:
22
26
  command: terraform plan
23
27
  alias: p
28
+ description: runs 'terraform plan'
24
29
  graph:
25
30
  command: terraform graph | dot -T pdf -o resource_graph.pdf
26
31
  alias: g
32
+ description: runs 'terraform graph'
27
33
  open-graph:
28
34
  command: ops graph && open resource_graph.pdf
29
35
  alias: og
36
+ description: opens the terraform graph with the OS 'open' command
@@ -1,18 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'secrets'
4
+
3
5
  # represents one action to be performed in the shell
4
6
  # can assemble a command line from a command and args
5
7
  class Action
6
- def initialize(command, args)
7
- @command = command
8
+ def initialize(config, args, options)
9
+ @config = config
8
10
  @args = args
11
+ @options = options
9
12
  end
10
13
 
11
14
  def run
15
+ load_secrets if load_secrets?
16
+
12
17
  Kernel.exec(to_s)
13
18
  end
14
19
 
15
20
  def to_s
16
- "#{@command} #{@args.join(' ')}"
21
+ "#{command} #{@args.join(' ')}"
22
+ end
23
+
24
+ def alias
25
+ @config["alias"]
26
+ end
27
+
28
+ def command
29
+ @config["command"]
30
+ end
31
+
32
+ def description
33
+ @config["description"]
34
+ end
35
+
36
+ private
37
+
38
+ def load_secrets?
39
+ @config["load_secrets"]
40
+ end
41
+
42
+ def load_secrets
43
+ Secrets.new(secrets_file).load
44
+ end
45
+
46
+ def secrets_file
47
+ `echo #{@options&.dig("secrets", "path")}`.chomp
17
48
  end
18
49
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AppConfig
4
+ def initialize(filename = "")
5
+ @filename = filename.empty? ? default_filename : filename
6
+ end
7
+
8
+ def load
9
+ config['environment']&.each do |key, value|
10
+ ENV[key] = value
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def default_filename
17
+ "config/#{environment}/config.json"
18
+ end
19
+
20
+ def config
21
+ @config ||= file_contents ? JSON.parse(file_contents) : {}
22
+ rescue JSON::ParserError => e
23
+ Output.error("Error parsing config data: #{e}")
24
+ {}
25
+ end
26
+
27
+ def file_contents
28
+ @file_contents ||= begin
29
+ File.open(@filename).read
30
+ rescue Errno::ENOENT
31
+ nil
32
+ end
33
+ end
34
+
35
+ def environment
36
+ ENV['environment']
37
+ end
38
+ end
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Builtin
4
+ class << self
5
+ def description
6
+ "no description"
7
+ end
8
+ end
9
+
4
10
  def initialize(args, config)
5
11
  @args = args
6
12
  @config = config
@@ -8,6 +8,12 @@ require 'builtins/helpers/dependency_handler'
8
8
 
9
9
  module Builtins
10
10
  class Down < Builtin
11
+ class << self
12
+ def description
13
+ "stops dependent services listed in ops.yml"
14
+ end
15
+ end
16
+
11
17
  def run
12
18
  # TODO: return a success/failure status to the caller
13
19
  unmeet_dependencies
@@ -39,7 +45,7 @@ module Builtins
39
45
  else
40
46
  Output.failed
41
47
  Output.error("Error unmeeting #{dependency.type} dependency '#{dependency.name}':")
42
- puts(dependency.output)
48
+ Output.out(dependency.output)
43
49
  end
44
50
  end
45
51
  end
@@ -5,12 +5,16 @@ require 'output'
5
5
 
6
6
  module Builtins
7
7
  class Env < Builtin
8
+ class << self
9
+ def description
10
+ "prints the current environment, e.g. 'dev', 'production', 'staging', etc."
11
+ end
12
+ end
13
+
8
14
  def run
9
15
  Output.print(environment)
10
16
  end
11
17
 
12
- private
13
-
14
18
  def environment
15
19
  ENV['environment']
16
20
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorize'
4
+
5
+ require 'builtin'
6
+
7
+ module Builtins
8
+ class Help < Builtin
9
+ class << self
10
+ def description
11
+ "displays available builtins and actions"
12
+ end
13
+ end
14
+
15
+ def run
16
+ Output.out("Builtins:")
17
+ Output.out(" #{builtins.join("\n ")}")
18
+ Output.out("")
19
+ Output.out("Actions:")
20
+ Output.out(" #{actions.join("\n ")}")
21
+ end
22
+
23
+ private
24
+
25
+ def builtins
26
+ builtin_class_names.map do |class_name|
27
+ description = Builtins.const_get(class_name).description
28
+ format("%<name>-35s %<desc>s", name: class_name.downcase.to_s.yellow, desc: description)
29
+ end
30
+ end
31
+
32
+ def builtin_class_names
33
+ Builtins.constants.select { |c| Builtins.const_get(c).is_a? Class }
34
+ end
35
+
36
+ def actions
37
+ @config["actions"].map do |name, value|
38
+ format("%<name>-35s %<desc>s", name: name.yellow, desc: value["description"] || value["command"])
39
+ end
40
+ end
41
+ end
42
+ end
@@ -12,6 +12,12 @@ module Builtins
12
12
  OPS_YML_TEMPLATE = File.join(TEMPLATE_DIR, "%<template_name>s.template.yml")
13
13
  DEFAULT_TEMPLATE_NAME = "ops"
14
14
 
15
+ class << self
16
+ def description
17
+ "creates an ops.yml file from a template"
18
+ end
19
+ end
20
+
15
21
  def run
16
22
  if File.exist?(OPS_YML)
17
23
  Output.error("File '#{OPS_YML} exists; not initializing.")
@@ -9,6 +9,12 @@ require 'output'
9
9
 
10
10
  module Builtins
11
11
  class Up < Builtin
12
+ class << self
13
+ def description
14
+ "attempts to meet dependencies listed in ops.yml"
15
+ end
16
+ end
17
+
12
18
  def run
13
19
  # TODO: return a success/failure status to the caller
14
20
  meet_dependencies
@@ -40,7 +46,7 @@ module Builtins
40
46
  else
41
47
  Output.failed
42
48
  Output.error("Error meeting #{dependency.type} dependency '#{dependency.name}':")
43
- puts(dependency.output)
49
+ Output.out(dependency.output)
44
50
  end
45
51
  end
46
52
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubygems"
4
+
5
+ require "output"
6
+
7
+ module Builtins
8
+ class Version < Builtin
9
+ GEMSPEC_FILE = "#{__dir__}/../../ops_team.gemspec"
10
+
11
+ class << self
12
+ def description
13
+ "prints the version of ops that is running"
14
+ end
15
+ end
16
+
17
+ def run
18
+ unless gemspec
19
+ Output.error("Unable to load gemspec at '#{GEMSPEC_FILE}")
20
+ return false
21
+ end
22
+
23
+ Output.out(gemspec.version)
24
+ end
25
+
26
+ private
27
+
28
+ def gemspec
29
+ @gemspec ||= Gem::Specification.load(GEMSPEC_FILE)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Environment
4
+ def initialize(env_hash)
5
+ @env_hash = env_hash
6
+ end
7
+
8
+ def set_variables
9
+ @env_hash.each do |key, value|
10
+ ENV[key] = value
11
+ end
12
+
13
+ ENV['environment'] = environment
14
+ end
15
+
16
+ def environment
17
+ return 'dev' if ENV['environment'].nil? || ENV['environment'].empty?
18
+
19
+ ENV['environment']
20
+ end
21
+ end
data/lib/ops.rb CHANGED
@@ -7,9 +7,10 @@ require 'require_all'
7
7
  require 'action'
8
8
  require 'output'
9
9
  require 'options'
10
+ require 'environment'
10
11
  require_rel "builtins"
11
12
 
12
- # executes commands defined in local `ops.yml`
13
+ # executes commands based on local `ops.yml`
13
14
  class Ops
14
15
  class UnknownActionError < StandardError; end
15
16
 
@@ -27,7 +28,8 @@ class Ops
27
28
  def run
28
29
  exit(INVALID_SYNTAX_EXIT_CODE) unless syntax_valid?
29
30
 
30
- ENV['environment'] ||= 'dev'
31
+ environment.set_variables
32
+ app_config.load
31
33
 
32
34
  return builtin.run if builtin
33
35
 
@@ -61,20 +63,16 @@ class Ops
61
63
  end
62
64
 
63
65
  def action
64
- @action ||= Action.new(command, @args)
65
- end
66
-
67
- def command
68
- @command ||= begin
69
- return actions[@action_name]["command"] if actions[@action_name]
70
- return aliases[@action_name]["command"] if aliases[@action_name]
66
+ return actions[@action_name] if actions[@action_name]
67
+ return aliases[@action_name] if aliases[@action_name]
71
68
 
72
- raise UnknownActionError, "Unknown action: #{@action_name}"
73
- end
69
+ raise UnknownActionError, "Unknown action: #{@action_name}"
74
70
  end
75
71
 
76
72
  def actions
77
- config["actions"]
73
+ config["actions"].transform_values do |config|
74
+ Action.new(config, @args, action_options)
75
+ end
78
76
  end
79
77
 
80
78
  def config
@@ -88,11 +86,31 @@ class Ops
88
86
 
89
87
  def aliases
90
88
  @aliases ||= begin
91
- actions.each_with_object({}) do |(_name, body), alias_hash|
92
- alias_hash[body["alias"]] = body if body.include?("alias")
89
+ actions.each_with_object({}) do |(_name, action), alias_hash|
90
+ alias_hash[action.alias] = action if action.alias
93
91
  end
94
92
  end
95
93
  end
94
+
95
+ def action_options
96
+ @action_options ||= @config.dig("options", "actions")
97
+ end
98
+
99
+ def env_vars
100
+ @config.dig("options", "environment") || {}
101
+ end
102
+
103
+ def environment
104
+ @environment ||= Environment.new(env_vars)
105
+ end
106
+
107
+ def app_config_file
108
+ `echo #{@options&.dig("config", "path")}`.chomp
109
+ end
110
+
111
+ def app_config
112
+ @app_config ||= AppConfig.new(app_config_file)
113
+ end
96
114
  end
97
115
 
98
116
  Ops.new(ARGV).run if $PROGRAM_NAME == __FILE__
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require 'output'
6
+ require 'app_config'
7
+
8
+ class Secrets < AppConfig
9
+ private
10
+
11
+ def default_filename
12
+ return default_ejson_filename if File.exist?(default_ejson_filename)
13
+
14
+ default_json_filename
15
+ end
16
+
17
+ def default_ejson_filename
18
+ "config/#{environment}/secrets.ejson"
19
+ end
20
+
21
+ def default_json_filename
22
+ "config/#{environment}/secrets.json"
23
+ end
24
+
25
+ def file_contents
26
+ @file_contents ||= @filename.match(/\.ejson$/) ? `ejson decrypt #{@filename}` : super
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'ops_team'
5
+ s.version = '0.2.4'
6
+ s.authors = [
7
+ 'nickthecook@gmail.com'
8
+ ]
9
+ s.date = '2020-05-29'
10
+ s.summary = 'ops_team handles basic operations tasks for your project, driven by YAML config'
11
+ s.homepage = 'https://github.com/nickthecook/ops'
12
+ s.files = Dir[
13
+ 'Gemfile',
14
+ 'bin/*',
15
+ 'lib/*',
16
+ 'etc/*',
17
+ 'lib/builtins/*',
18
+ 'lib/builtins/helpers/*',
19
+ 'lib/dependencies/*',
20
+ 'loader.rb',
21
+ 'ops_team.gemspec'
22
+ ]
23
+ s.executables << 'ops'
24
+ s.required_ruby_version = '~> 2.5'
25
+ s.add_runtime_dependency 'colorize', '~> 0.8', '>= 0.8.1'
26
+ s.add_runtime_dependency 'require_all', '~> 1.1', '>= 1.1.6'
27
+ s.license = 'GPL-3.0-only'
28
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ops_team
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - nickthecook@gmail.com
@@ -59,17 +59,22 @@ extra_rdoc_files: []
59
59
  files:
60
60
  - Gemfile
61
61
  - bin/ops
62
+ - bin/print_config
63
+ - bin/print_secrets
62
64
  - bin/tag
63
65
  - etc/ops.template.yml
64
66
  - etc/ruby.template.yml
65
67
  - etc/terraform.template.yml
66
68
  - lib/action.rb
69
+ - lib/app_config.rb
67
70
  - lib/builtin.rb
68
71
  - lib/builtins/down.rb
69
72
  - lib/builtins/env.rb
73
+ - lib/builtins/help.rb
70
74
  - lib/builtins/helpers/dependency_handler.rb
71
75
  - lib/builtins/init.rb
72
76
  - lib/builtins/up.rb
77
+ - lib/builtins/version.rb
73
78
  - lib/dependencies/apk.rb
74
79
  - lib/dependencies/apt.rb
75
80
  - lib/dependencies/brew.rb
@@ -80,10 +85,13 @@ files:
80
85
  - lib/dependencies/gem.rb
81
86
  - lib/dependencies/terraform.rb
82
87
  - lib/dependency.rb
88
+ - lib/environment.rb
83
89
  - lib/ops.rb
84
90
  - lib/options.rb
85
91
  - lib/output.rb
92
+ - lib/secrets.rb
86
93
  - loader.rb
94
+ - ops_team.gemspec
87
95
  homepage: https://github.com/nickthecook/ops
88
96
  licenses:
89
97
  - GPL-3.0-only