Giter VIP home page Giter VIP logo

salty-dog's Introduction

Salty Dog

salty-dog is a tool to validate JSON and YAML data using JSON schema rules. It can filter elements and validate select parts of the document, supports multiple documents in the same stream or file, and can insert defaults during validation.

Check out the getting started guide.

Contents

Status

Pipeline status MIT license Renovate badge Known vulnerabilities

Open bug count Open issue count Closed issue count

Lines of Code Test coverage Technical debt ratio

Maintainability score Quality issues FOSSA Status

Releases

github release link github release version github commits since release

npm package link npm release version Typescript definitions

docker image link docker image size

Build

salty-dog is written in Typescript and requires make, node, and yarn to build. It can be built locally or in a container.

Please see the build docs for more details.

Usage

salty-dog is distributed as a docker container and an npm package.

While the container is the preferred way of running salty-dog, it has one limitation: docker run combines stdout and stderr, making it impossible to separate logs and the output document. Writing either the logs or dest to a file works around this.

Using The Container

To run the Docker container: docker run --rm ssube/salty-dog:master

The latest semi-stable image is published to ssube/salty-dog:master. Containers are published based on both Alpine Linux and Debian (currently Stretch). All of the available tags are listed here.

Rules are provided in the image at /salty-dog/rules. To use custom rules in the container, mount them with -v $(pwd)/rules:/salty-dog/rules:ro and load them with --rules /rules/foo.yml.

The ssube/salty-dog container image can be run normally or interactively.

To validate a file or input normally:

> docker run --rm ssube/salty-dog:master --help

You can also launch a shell within the container, using local rules:

> docker run \
    --rm \
    -it \
    --entrypoint bash \
    ssube/salty-dog:master

Using The Package

salty-dog is also published as an npm package with a binary, so it can be used as a CLI command or programmatically.

Project Package

To install salty-dog for the current project:

> yarn add -D salty-dog
> $(yarn bin)/salty-dog --help

Global Package

It is also possible to install salty-dog globally, rather than within a project. However, this is not recommended.

> yarn global add salty-dog
> export PATH="${PATH}:$(yarn global bin)"
> salty-dog --help

Usage Modes

salty-dog can run in a few different modes: check mode will report errors, fix mode will attempt to modify the input document, and list mode will print the active set of rules.

Check Mode

By default, salty-dog will validate the structure and contents of the --source document. If all rules pass, the document will be printed to --dest.

> cat examples/kubernetes-resources-pass.yml | salty-dog \
    --rules rules/kubernetes.yml \
    --tag kubernetes

...
[2019-06-15T23:53:34.223Z]  INFO: salty-dog/19839 on cerberus: all rules passed

> cat examples/kubernetes-resources-fail.yml | salty-dog \
    --rules rules/kubernetes.yml \
    --tag kubernetes

...
[2019-06-15T23:56:04.764Z] ERROR: salty-dog/22211 on cerberus: some rules failed (errors=1)

The --source and --dest default to stdin and stdout, respectively, but a path may be provided:

> salty-dog \
    --rules rules/kubernetes.yml \
    --tag kubernetes \
    --source examples/kubernetes-resources-pass.yml \
    --dest /tmp/kubernetes-resource.yml

...
[2019-06-15T23:53:34.223Z]  INFO: salty-dog/19839 on cerberus: all rules passed

Fix Mode

salty-dog can also add default values to missing properties in fix mode. If a rule does not immediately pass with the --source document, but defaults are provided in the schema, the defaults will be inserted before printing to --dest.

> salty-dog fix \
    --source examples/kubernetes-resources-some.yml \
    --rules rules/kubernetes.yml \
    --tag kubernetes
Default Values

Properties that appear in the schema with a default provided will be added to each element as it is checked. Rules apply in order, as do their defaults.

Coercing Values

Properties that appear in the document with a different type than they have in the schema may be coerced, if the value is compatible with the schema type. The full matrix of valid type coercions is documented by Ajv.

List Mode

salty-dog can list the active set of rules, to help debug tags and inclusion. Both --source and --dest are ignored in list mode.

> salty-dog list \
    --rules rules/kubernetes.yml \
    --tag kubernetes

...
[2019-06-30T18:39:11.930Z]  INFO: salty-dog/26330 on cerberus: listing active rules
    rules: [
      {
        "desc": "resource limits are too low",
        "level": "debug",
        "name": "kubernetes-resources-minimum-cpu",

...
    ]

Formatting Logs

salty-dog uses node-bunyan for logging and prints structured JSON output. Logs can be pretty-printed by redirecting stderr through bunyan itself or jq, both of which are installed in the salty-dog container:

> cat resource.yml | salty-dog --rules rules/kubernetes.yml --tag kubernetes 2> >(bunyan)

...
[2019-06-15T23:53:34.223Z]  INFO: salty-dog/19839 on cerberus: all rules passed

> cat resource.yml | salty-dog --rules rules/kubernetes.yml --tag kubernetes 2> >(jq)

...
{
  "name": "salty-dog",
  "hostname": "cerberus",
  "pid": 19839,
  "level": 30,
  "msg": "all rules passed",
  "time": "2019-06-15T23:53:34.223Z",
  "v": 0
}

Using jq allows for additional filtering and formatting. For example, jq 'select(.level > 30)' will only print warnings and errors (the minimum log level to print can be set in the configuration file).

To print the last line's message and error messages: tail -1 | jq '[.msg, try (.errors[] | .msg)]'

> cat test/examples/kubernetes-resources-high.yml | salty-dog \
    --rules rules/kubernetes.yml \
    --tag kubernetes 2> >(tail -1 | jq '[.msg, try (.errors[] | .msg)]')

[
  "all rules passed"
]

> cat test/examples/kubernetes-resources-some.yml | salty-dog \
    --rules rules/kubernetes.yml \
    --tag kubernetes 2> >(tail -1 | jq '[.msg, try (.errors[] | .msg)]')

[
  "some rules failed",
  ".resources.limits should have required property 'memory' at $.spec.template.spec.containers[*] for kubernetes-resources",
  ".metadata should have required property 'labels' at $ for kubernetes-labels"
]

Rules

Rules combine a jsonpath expression and JSON schema to select and validate the document.

The rule's select expression is used to select nodes that should be validated, which are filtered, then checked.

The structure of rule files and the rules within them are documented here.

Loading Rule Sources

Rules can be loaded from a file, module, or path.

To load a file by name, --rule-file foo.yml. This will accept any extension.

To load a module, --rule-module foo. The required module exports are documented here.

To load a path, --rule-path foo/. This will recursively load any files matching *.+(json|yaml|yml).

Using Rule Tags

All rules are disabled by default and must be enabled by name, level, or tag.

To enable a single rule by name, --include-name foo-rule.

To enable a group of rules by level, --include-level warn.

To enable a group of rules by tag, --include-tag foo.

Validating Rules

To validate the rules in the rules/ directory using the meta-rules:

> make test-rules

...
{"name":"salty-dog","hostname":"cerberus","pid":29403,"level":30,"msg":"all rules passed","time":"2019-06-16T00:56:55.132Z","v":0}

License

FOSSA Status

salty-dog's People

Contributors

dependabot[bot] avatar isolex[bot] avatar renovate-bot avatar renovate[bot] avatar ssube avatar

Stargazers

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

Watchers

 avatar  avatar  avatar

salty-dog's Issues

write more rules

Write more rules: useful examples are better than arbitrary ones, and tons of existing tools store their config in JSON or YAML.

Requirements:

  • stored as JSON or YAML
  • reasonably well-defined schema
  • actual best practices that can be described as rules

Tools:

short aliases for common options

Summary

Add short aliases for help and the other include options, to match -v for --version and -t for --include-tag.

Scope

  • --help: -h
  • --include-level: -l, --level
  • --include-name: -n, --name

Use Case

The most common options should have single-letter aliases.

The --include-* options are the "default" way to filter rules (exclusion is more complicated and less useful), and --include-tag is already aliased to --tag and -t.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.


Warning

Renovate failed to look up the following dependencies: Failed to look up npm package @apextoaster/js-utils, Failed to look up npm package @apextoaster/js-yaml-schema, Failed to look up npm package @istanbuljs/nyc-config-typescript, Failed to look up npm package @istanbuljs/schema, Failed to look up npm package @microsoft/api-documenter, Failed to look up npm package @microsoft/api-extractor, Failed to look up npm package @types/bunyan, Failed to look up npm package @types/chai, Failed to look up npm package @types/chai-as-promised, Failed to look up npm package @types/deep-diff, Failed to look up npm package @types/js-yaml, Failed to look up npm package @types/lodash, Failed to look up npm package @types/minimatch, Failed to look up npm package @types/mocha, Failed to look up npm package @types/node, Failed to look up npm package @types/sinon, Failed to look up npm package @types/sinon-chai, Failed to look up npm package @types/source-map-support, Failed to look up npm package @types/yargs, Failed to look up npm package @typescript-eslint/eslint-plugin, Failed to look up npm package @typescript-eslint/parser, Failed to look up npm package ajv, Failed to look up npm package bunyan, Failed to look up npm package c8, Failed to look up npm package chai, Failed to look up npm package chai-as-promised, Failed to look up npm package deep-diff, Failed to look up npm package esbuild, Failed to look up npm package eslint, Failed to look up npm package eslint-plugin-chai, Failed to look up npm package eslint-plugin-chai-expect, Failed to look up npm package eslint-plugin-chai-expect-keywords, Failed to look up npm package eslint-plugin-import, Failed to look up npm package eslint-plugin-mocha, Failed to look up npm package eslint-plugin-no-null, Failed to look up npm package eslint-plugin-sonarjs, Failed to look up npm package js-yaml, Failed to look up npm package jsonpath-plus, Failed to look up npm package lodash, Failed to look up npm package memfs, Failed to look up npm package minimatch, Failed to look up npm package mocha, Failed to look up npm package noicejs, Failed to look up npm package nyc, Failed to look up npm package sinon, Failed to look up npm package sinon-chai, Failed to look up npm package source-map-support, Failed to look up npm package standard-version, Failed to look up npm package typescript, Failed to look up npm package yargs.

Files affected: package.json


Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
Dockerfile.alpine
  • docker.artifacts.apextoaster.com/library/node 19-alpine
Dockerfile.stretch
  • docker.artifacts.apextoaster.com/library/node 17-stretch
gitlabci
.gitlab/ci-tools.yml
  • docker.artifacts.apextoaster.com/apextoaster/base 1.5
  • docker.artifacts.apextoaster.com/apextoaster/code-climate 0.6
  • docker.artifacts.apextoaster.com/apextoaster/docker 20.10
  • docker.artifacts.apextoaster.com/apextoaster/docker-dind 20.10
  • docker.artifacts.apextoaster.com/apextoaster/node 16.19
  • docker.artifacts.apextoaster.com/apextoaster/sonar-scanner 4.4
npm
package.json
  • @apextoaster/js-utils 0.5.0
  • @apextoaster/js-yaml-schema 0.5.0
  • @istanbuljs/nyc-config-typescript 1.0.2
  • @istanbuljs/schema 0.1.3
  • @microsoft/api-documenter 7.22.8
  • @microsoft/api-extractor 7.35.1
  • @types/bunyan 1.8.8
  • @types/chai 4.3.5
  • @types/chai-as-promised 7.1.5
  • @types/deep-diff 1.0.2
  • @types/js-yaml 4.0.5
  • @types/lodash 4.14.195
  • @types/minimatch 5.1.2
  • @types/mocha 10.0.1
  • @types/node 18.15.3
  • @types/sinon 10.0.15
  • @types/sinon-chai 3.2.9
  • @types/source-map-support 0.5.6
  • @types/yargs 17.0.24
  • @typescript-eslint/eslint-plugin 5.59.8
  • @typescript-eslint/parser 5.59.8
  • ajv 8.12.0
  • bunyan 1.8.15
  • c8 7.14.0
  • chai 4.3.7
  • chai-as-promised 7.1.1
  • deep-diff 1.0.2
  • esbuild 0.18.5
  • eslint 8.41.0
  • eslint-plugin-chai 0.0.1
  • eslint-plugin-chai-expect 3.0.0
  • eslint-plugin-chai-expect-keywords 2.1.0
  • eslint-plugin-import 2.27.5
  • eslint-plugin-mocha 10.1.0
  • eslint-plugin-no-null 1.0.2
  • eslint-plugin-sonarjs 0.19.0
  • js-yaml 4.1.0
  • jsonpath-plus 7.2.0
  • lodash 4.17.21
  • memfs 3.5.1
  • minimatch 5.1.6
  • mocha 10.2.0
  • noicejs 4.0.0
  • nyc 15.1.0
  • sinon 15.1.0
  • sinon-chai 3.7.0
  • source-map-support 0.5.21
  • standard-version 9.5.0
  • typescript 4.9.5
  • yargs 17.7.2
  • lodash 4.17.21

  • Check this box to trigger a request for Renovate to run again on this repository

putting chai in the test chunk causes tests to throw

Adding chai to the test chunk via manualChunks (id.includes('/chai/')) causes the test run to throw an error:

created out/ in 5s
/home/ssube/code/ssube/salty-dog//node_modules/.bin/mocha /home/ssube/code/ssube/salty-dog//out/test.js
/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:1163
      else throw err
           ^

TypeError: __chunk_1.createCommonjsModule is not a function
    at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/out/vendor.js:3899:29)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (internal/modules/cjs/helpers.js:14:16)
    at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/out/test.js:6:17)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Module.require (internal/modules/cjs/loader.js:723:19)
    at require (internal/modules/cjs/helpers.js:14:16)
    at /home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:330:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:327:14)
    at Mocha.run (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:804:10)
    at Object.exports.singleRun (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run-helpers.js:207:16)
    at exports.runMocha (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run-helpers.js:300:13)
    at Object.exports.handler.argv [as handler] (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run.js:296:3)
    at Object.runCommand (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/lib/command.js:242:26)
    at Object.parseArgs [as _parseArgs] (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:1087:28)
    at Object.parse (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:566:25)
    at Object.exports.main (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/cli.js:63:6)
    at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/node_modules/mocha/bin/_mocha:10:23)
    at Module._compile (internal/modules/cjs/loader.js:816:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
    at Module.load (internal/modules/cjs/loader.js:685:32)
    at Function.Module._load (internal/modules/cjs/loader.js:620:12)
    at Function.Module.runMain (internal/modules/cjs/loader.js:877:12)
    at internal/main/run_main_module.js:21:11
Makefile:83: recipe for target 'test' failed
make: *** [test] Error 1

Fix that and get test deps out of the vendor chunk.

install bunyan and jq in containers

Feature

The examples use bunyan and/or jq to filter logs, but neither is present in the containers. Both are available from standard package repositories.

Summary

Filtering and formatting logs is pretty useful.

Scope

  • install jq
  • install bunyan globally
  • add yarn global bin to path
  • clean up caches

interactive diff mode

With #3 implemented, offer a way to accept or roll back changes.

For each rule, if the working copy differs from the original data:

  • show the diff
  • prompt to accept, revert, or cancel
  • apply or discard changes to data

schema fragments

Add a fragments or definitions block to the rules files, defining schema fragments that will be added before the rules are run.

This will allow shared object definitions and DRY up the rule bodies.

Alpine Docker image

Hello,

Here is my Dockerfile to use Alpine Linux instead of Debian and build in a container. I ended up with an ~83MB image.

FROM node:11-alpine AS build

RUN apk add -U --no-cache build-base # Add git to run git commands in make
COPY . /salty-dog
WORKDIR /salty-dog
RUN make

FROM node:11-alpine

# copy config, which changes rarely
COPY docs/config-docker.yml /root/.salty-dog.yml

# copy package first, to invalidate other layers when version changes
COPY package.json /salty-dog/package.json

# copy chunks, largest to smallest (entrypoint)
COPY --from=build /salty-dog/out/vendor.js /salty-dog/out/vendor.js
COPY --from=build /salty-dog/out/main.js /salty-dog/out/main.js
COPY --from=build /salty-dog/out/index.js /salty-dog/out/index.js

# set up as global cli tool
WORKDIR /salty-dog
RUN yarn global add file:$(pwd)
ENV PATH="${PATH}:$(yarn global bin)"

COPY rules /salty-dog/rules

ENTRYPOINT [ "node", "/salty-dog/out/index.js" ]
CMD [ "--help" ]

It also implies minor changes to test-examples.sh to make it shell compliant.

Do you see any problem moving to Alpine ? If any, we may simply add a new image with a specific tag alpine.
I can make a PR if you want.

improve diffs

Like #20 did for errors, improve the diff messages to print the operation being performed and path where it occurs. This will depend on #21 and correctly-typed context data being passed along with the visitor.

Access yaml frontmatter

Is it possible to access the yaml frontmatter? I'd like to be able to set some details and tags up there

make mutate an option within fix mode

Summary

The mutate option, used to apply deep-diffs to the target object, is currently being inferred based on mode === MODE.fix, with no way to turn it off.

Scope

  • add mutate option under fix command

Use Case

  • print diffs without applying them (dry-run)

Questions

This will be replaced, in part, by #21 and #133.

stdin/stdout mode

To validate a pipe between commands, the CLI should have options to set input to stdin and output to stdout. For example: jinja foo.tpl | salty-dog --mode fail --source - --dest - | kubectl apply -f -

load rules from directory

As a convenience, allow --rules to take a directory, and load rules from each .yml file within that directory. Optionally recurse.

fix untyped flash data

The context data used to pass selected item index and rule name down is untyped and not particularly flexible.

Passing arbitrary data down will never be possible to type well, but using context hooks (#21) to pass errors and diffs up as they are encountered will allow the friendly messaging to happen in a more appropriate place. Since that place will know what rule produced the messages, it could even call some sort of Rule.format method.

streamed errors do not cause rule failure

Passing rule errors through ctx.error(err) as they occur causes them to be added directly to the context's error buffer without going through the end-of-rule result.errors.length > 0 check, causing the rule to appear as though it passed. The program as a whole still exits with the correct status and error count, since the errors are added to the context, but not attributed to the correct rule.

improve error messages

The raw error messages from Ajv and diffs from deep-diff are not the most readable, but are wonderfully detailed:

{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":20,"item":{"metadata":{"name":"example"},"spec":{"template":{"spec":{"containers":[{"name":"test"}]}}}},"msg":"checking item","time":"2019-07-01T14:09:15.175Z","v":0}
{"name":"kubernetes-labels","hostname":"cerberus","pid":23892,"level":40,"errors":[{"keyword":"required","dataPath":".metadata","schemaPath":"#/properties/metadata/required","params":{"missingProperty":"labels"},"message":"should have required property 'labels
'"}],"item":{"metadata":{"name":"example"},"spec":{"template":{"spec":{"containers":[{"name":"test"}]}}}},"rule":{"desc":"all resources should have labels","level":"info","name":"kubernetes-labels","select":"$","tags":["kubernetes","labels"],"check":{"type":"o
bject","required":["metadata"],"properties":{"metadata":{"type":"object","required":["labels"],"properties":{"labels":{"type":"object","additionalProperties":false,"patternProperties":{"^[-.a-z0-9]{1,63}$":{"type":"string"}}}}}}}},"msg":"rule failed on item","
time":"2019-07-01T14:09:15.175Z","v":0}                       
{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":40,"count":1,"rule":{"desc":"all resources should have labels","level":"info","name":"kubernetes-labels","select":"$","tags":["kubernetes","labels"],"check":{"type":"object","required":["metadata"],
"properties":{"metadata":{"type":"object","required":["labels"],"properties":{"labels":{"type":"object","additionalProperties":false,"patternProperties":{"^[-.a-z0-9]{1,63}$":{"type":"string"}}}}}}}},"msg":"rule failed","time":"2019-07-01T14:09:15.175Z","v":0}
{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":50,"count":2,"errors":[{"keyword":"required","dataPath":"","schemaPath":"#/required","params":{"missingProperty":"resources"},"message":"should have required property 'resources'"},{"keyword":"requi
red","dataPath":".metadata","schemaPath":"#/properties/metadata/required","params":{"missingProperty":"labels"},"message":"should have required property 'labels'"}],"msg":"some rules failed","time":"2019-07-01T14:09:15.175Z","v":0}

Parts:

load rule modules

Rather than loading all rules from files, add a way to require modules that export rules: Array<RuleData>.

document workflow

Document the project workflow (or copy it from isolex), make issue labels, add issue templates, etc.

support different rule implementations

While the base SchemaRule can do a lot, future rules may need more logic or use a different kind of schema. This will be especially important with #6 and external rules.

Wire up DI through https://github.com/ssube/noicejs and await container.create(rule.type) should solve that neatly. Rule modules can provide DI modules if they have additional Parser or Rule classes.

validate config and rules while loading

The salty-dog-meta rules should be able to validate --rules source files and the config after they have been loaded and parsed.

  • add config to meta rules
  • compile meta rules into bundle
  • validate config
  • validate rules

visitor context hooks

Add hooks to the visitor context so callers can be notified at various important times, including:

  • item:
    • check (start)
    • skip (end - skip)
    • visited (start)
    • diff (mid - block)
    • error (end - fail)
    • pass (end - pass)
  • rule:
    • visited (start)
    • error (end - fail)
    • pass (end - pass)

Along the way:

  • push error formatting up to the hooks

handle multiple documents

The YAML parser supports multiple documents per file, which is fairly common among k8s resources. While cleaning up the walker/visitor, add a top-level loop for multiple documents.

include item index in error messages

This didn't make #112, but to complete #20 for errors, the selected item's index (out of all selected items, before filtering) should be included in the error message and data.

This will require moving the map(friendlyError) call up into the visitor to some extent, although schema rules should not leak raw Ajv errors.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

v0.9 image fails trying to load schema from current directory

Bug

Something is broken!

Summary

Error loading schema to validate config since v0.9 image was published.

Steps to Reproduce

  • run the docker image with cjs bundle

Actual Behavior

uncaught error during main: Error: ENOENT: no such file or directory, open '/build/src/git.company.com/sKSMtss1/1/x/y/z/rules/salty-dog.yml'
    at Object.openSync (node:fs:585:3)
    at readFileSync (node:fs:453:35)
    at loadSchema (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33664:44)
    at validateConfig (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33687:33)
    at main (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33775:8) {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '/build/src/git.company.com/sKSMtss1/1/x/y/z/rules/salty-dog.yml'
}

Expected Behavior

Should load the config from /salty-dog/rules/salty-dog.yml (or ../../rules, relative to the entrypoint script), whether that is /salty-dog/out/bundle/index.cjs or /salty-dog/out/src/index.js.

shell completion command

Yargs offers bash/zsh completion, as an option or command. Set that up and look into whether the --mode option should, in fact, be the command.

set up build tools

Set up a pipeline, publish packages and images, and run all manner of quality assurance bots.

  • gitlab pipeline
    • build & test
    • publish image
    • publish package
  • renovate
  • code climate
  • sonar cloud

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.