Giter Club home page Giter Club logo

crops's People

Contributors

leshaunj avatar nickthecook avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

crops's Issues

Allow defined 'init' actions to override the built-in

Current behaviour

You can't create ops init actions because it is a built-in.

Desired behaviour

Defining an ops init action is treated like any other action.

Rationale

init is a common keyword that might be used with ops, but ops init is only useful once per project, if ever; it doesn't serve any purpose once ops.yaml exists.

If an ops init action is defined, then the ops.yaml file already exists! So at that point ops init can no longer serve its built-in purpose.

Explore using Output class to silence notices instead of env var

The -q/--quiet command-line option is implemented by setting an env var that Runner will check before doing an Output.notice("Running 'some-action' ..."). Other than this one, env vars are otherwise used to give ops input or set options.

Since:

  • other than this one case, classes just call Output.something to print and let Output handle whether to print it or not, and how to display it
  • Output already has Output.silence method that can be called to change what it prints and what it doesn't

the -q option could be implemented by calling a new method, Output.silence_notices, which would set a class var in Output, which it would use to decide whether or not to print notices.

sshkey dependency should fail if provided empty key name

Situation:

dependencies:
  sshkey:
    - ""

Expected Behaviour:

> ops up
[Sshkey]                             FAILED
Bad Key Name?
>
  • No sshkey files should be created

Actual Behaviour:

> ops up
[Sshkey]
No passphrase set for SSH key ''
Unhandled exception: Error opening file with mode 'r': '': No such file or directory (File::NotFoundError)
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'raise<File::Error+>:NoReturn'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'Dependencies::Helpers::SshKeyDecryptor#plaintext_key:(String | Nil)'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'Builtins::Common::UpDown+@Builtins::Common::UpDown#meet_dependencies:Nil'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'Builtins::Common::UpDown+@Builtins::Common::UpDown#run:Bool'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'Ops#run:(Bool | Nil)'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in '__crystal_main'
  from /usr/local/Cellar/ops/2.2.0/bin/ops in 'main'
  from /usr/lib/dyld in 'start'
>
> ls
-q	-q.pub	ops.yml

Fall back to global 'ops.yaml' when no action found

If the current directory ./ops.yaml does not have the action to run, fall back to a 'global' ~/.ops.yaml file (path configurable). Actions in this file should be prioritized over built-ins, except perhaps init when no current directory ./ops.yaml exists (potentially configurable).

Example 1

  1. Current directory ./ops.yaml exists and has an apply action.
  2. Global ~/.ops.yaml has an apply action.
  3. User runs ops apply and the action in working directory ./ops.yaml is run.

Example 2

  1. Current direcotry ./ops.yaml exists but has no apply action.
  2. Global ~/.ops.yaml has an apply action.
  3. User runs ops apply and the action in global ~/ops.yaml is run.

Example 3

  1. Current directory ./ops.yaml does not exist.
  2. Global ~/ops.yaml has an apply action.
  3. User runs ops apply and the action in global ~/ops.yaml is run.

Example 4

  1. Current directory ./ops.yaml doesn't exist.
  2. Global ~/.ops.yaml has an init action.
  3. User runs ops init. Current directory ./ops.yaml is created. No action in global ~/.ops.yaml is run.
  4. Current directory ./ops.yaml exists but has no init action.
  5. User runs ops init and the action in global ~/.ops.yamlis run.

Example 5

  1. Current directory ./ops.yaml but has no init action.
  2. Global ~/.ops.yaml has an init action.
  3. User runs ops init and the action in global ~/.ops.yaml is run.

Edge cases

Should still work when current directory ./ops.yaml and global ~/.ops.yaml are the same file.

options.up.exit_on_error does not stop processes dependecies on error

Situation:

dependencies:
  custom:
    - true
    - false
    - true
options:
  up:
    exit_on_error: true

Expected Behaviour:

> ops up
[Custom] true                                      OK
[Custom] false                                     FAILED

Error meeting Custom dependency 'false':
>

Actual Behaviour:

> ops up
[Custom] true                                      OK
[Custom] false                                     FAILED
[Custom] true                                      OK
>

'ops init' checks for 'ops.yml' instead of 'ops.yaml'

Version: 2.0.6

ops init always tries to create ops.yml instead of ops.yaml. This happens even if you have an ops.yaml file—
it only checks for ops.yml.

Expected behaviour

  • If ops.yaml exists, do not create ops.yml. Give the error saying ops.yaml already exists.
  • If ops.yml exists, do not create ops.yaml. Give the error saying ops.yml already exists.
  • If neither ops.yaml or ops.yml exist, create ops.yaml.
  • If both ops.yaml and ops.yml exist, give the error saying ops.yaml already exists.
  • If ops was invoked with the -f/-file option, error if said file already exists, and create the file otherwise.

envdiff fails when "options.envdiff.ignored_keys" is set

Symptoms

For instance:

# ops.yml
options:
  envdiff:
    ignored_keys:
      - TF_VAR_something
  exec:

Fails with:

ops envdiff test staging
Unhandled exception: Option 'envdiff.ignored_keys' must be an array of strings; got YAML::Any. (Options::OptionsError)
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in 'raise<Options::OptionsError>:NoReturn'
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in 'Builtins::Envdiff#keys_for<String>:Array(String)'
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in 'Builtins::Envdiff#source_only_keys:Array(String)'
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in 'Ops#run:(Bool | Nil)'
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in '__crystal_main'
  from /Users/username/.gem/ruby/2.7.4/gems/ops_team-2.0.6.rc1/build/darwin_arm64/ops in 'main'

Meanwhile:

# ops.yml
options:
  # envdiff:
    # ignored_keys:
      # - TF_VAR_something
  exec:

Is business as usual:

ops envdiff test staging
Environment 'test' defines keys that 'staging' does not:

   - [CONFIG] TF_VAR_something

Environment 'staging' defines keys that 'test' does not:

   - [CONFIG] TF_VAR_something_else

Diagnosis

From what I can see, Builtins::Envdiff is doing it's job:

option = Options.get("envdiff.ignored_keys")
if option.nil?
[] of String
else
raise Options::OptionsError.new("Option 'envdiff.ignored_keys' must be an array of strings; got #{option.class.name}.") unless option.is_a?(Array(String))

This, due to the nature of Options#get, as there's no way to know what type the specified option may be at compile time; hence, YAML::Any | Nil makes sense as it's return type:

crops/src/options.cr

Lines 9 to 12 in f4cfdad

def self.get(path) : YAML::Any | Nil
env_var_path = env_var(path)
env_var = ENV.keys.includes?(env_var_path) ? ENV[env_var_path] : nil
return YAML.parse(env_var) unless env_var.nil?

Suggestion

Off the top of my head (and limited crystal knowledge), something like the following may do the trick:

# crops/src/builtins/envdiff.cr
module Builtins
    class Envdiff < Builtin
        # ...
        private def ignored_keys : Array(String)
            @ignored_keys ||= begin
# -             option = Options.get("envdiff.ignored_keys")
                option = Options.get("envdiff.ignored_keys").as?(Array(String))

                if option.nil?
                    [] of String
                else
                    raise Options::OptionsError.new("Option 'envdiff.ignored_keys' must be an array of strings; got #{option.class.name}.") unless option.is_a?(Array(String))

                    option
                end
            end
        end
    end
end

From the crystal docs:

The as? pseudo-method is similar to as, except that it returns nil instead of raising an exception when the type doesn't match. It also can't be used to cast between pointer types and other types.

'.yaml' extension not supported on forwards

Issue

In version 1.21.1, I can use a forward to an ops.yaml in another directory. Version 2.0.2 also supports ops.yaml when running in the same directory as the file.

But whenever I try to use a forward to another ops.yaml, I get an error saying ops.yml does not exist, and the action does not run. If I rename the second ops.yaml to ops.yml, it will work as normal.

Expected behaviour

Forwards work with an ops.yaml file in the target directory.

Affected versions

2.0.0.rc14 and later

Additional notes

In an older version, I may have gotten the error, but the action ran anyway. I can't reproduce this anymore.

Example

./ops.yaml file
forwards:
  dir: directory

./directory/ops.yaml exists and is a valid ops.yaml with dependencies and actions. No ops.yml files exist.

Attempting to run the action
$ ops dir up
Forwarding 'ops up' to 'directory'...
File 'ops.yml' does not exist.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.