• Stars
    star
    957
  • Rank 45,928 (Top 1.0 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Because no one should be shell-scripting inside a JSON file.

scripty

Latest npm release Test Status

What is?

Using npm-scripts has become a popular way of maintaining the various build tasks needed to develop Node.js modules. People like npm-scripts because it's simple! This is a common refrain:

Don't bother with grunt, gulp, or broccoli, just add a little script to your package.json and run it with npm run name:of:script

Indeed, this is much simpler, but it can quickly become a mess. Take a look at what happened to our testdouble.js library's package.json. Using npm-scripts for everything is simple to start with, but it can't hope to guard against the complexity that naturally accumulates over the life of a project.

We wrote scripty to help us extract our npm scripts—particularly the gnarly ones—into their own files without changing the command we use to run them. To see how to do this yourself, read on!

Install

$ npm install --save-dev scripty

Usage

  1. From your module's root, create a scripts directory
  2. If you want to define an npm script named "foo:bar", write an executable file at scripts/foo/bar
  3. Feel a liberating breeze roll over your knuckles as your script is free to roam within its own file, beyond the stuffy confines of a quote-escaped string inside a pile of JSON
  4. Declare your "foo:bar" script in "scripts" in your package.json:
"scripts": {
  "foo:bar": "scripty"
}

From this point on, you can run npm run foo:bar and scripty will use npm's built-in npm_lifecycle_event environment variable to look up scripts/foo/bar and execute it for you.

This pattern is great for extracting scripts that are starting to become unwieldy inside your package.json, while still explicitly calling out the scripts that your package supports (though where to take that aspect from here is up for debate).

Advanced Usage

Ready to take things to the next level? Check this stuff out:

Passing command-line args

To pass command-line args when you're running an npm script, set them after -- and npm will forward them to your script (and scripty will do its part by forwarding them along).

For example, if you had a script in scripts/echo/hello:

#!/usr/bin/env sh

echo Hello, "$1"!

Then you can run npm run echo:hello -- WORLD and see your script print "Hello, WORLD!".

Batching "sub-scripts"

Let's say you have two test tasks in scripts/test/unit and scripts/test/integration:

"scripts": {
  "test:unit": "scripty",
  "test:integration": "scripty"
}

And you want npm test to simply run all of them, regardless of order. In that case, just add a "test" entry to your package.json like so:

"scripts": {
  "test:unit": "scripty",
  "test:integration": "scripty",
  "test": "scripty"
}

And from then on, running npm test will result in scripty running all the executable files it can find in scripts/test/*.

Defining an explicit parent script

Suppose in the example above, it becomes important for us to run our scripts in a particular order. Or, perhaps, when running npm test we need to do some other custom scripting as well. Fear, not!

Without changing the JSON from the previous example:

"scripts": {
  "test:unit": "scripty",
  "test:integration": "scripty",
  "test": "scripty"
}

Defining a script named scripts/test/index will cause scripty to only run that index script, as opposed to globbing for all the scripts it finds in scripts/test/*.

Running scripts in parallel

If you have a certain command that will match mutiple child scripts (for instance, if npm run watch matches scripts/watch/js and scripts/watch/css), then you can tell scripty to run the sub-scripts in parallel by setting a SCRIPTY_PARALLEL env variable to 'true'. This may be used to similar effect as the npm-run-all module.

To illustrate, to run a scripty script in parallel, you might:

$ SCRIPTY_PARALLEL=true npm run watch

Or, if that particular script should always be run in parallel, you can set the variable in your package.json:

"scripts": {
  "watch": "SCRIPTY_PARALLEL=true scripty"
}

Which will run any sub-scripts in parallel whenever you run npm run watch.

Finally, if you always want to run scripts in parallel, any option can be set in your package.json under a "scripty" entry:

"config": {
  "scripty": {
    "parallel": true
  }
}

Windows support

Windows support is provided by scripty in two ways:

  1. If everything in your scripts directory can be safely executed by Windows, no action is needed (this is only likely if you don't have collaborators on Unix-like platforms)
  2. If your project needs to run scripts in both Windows & Unix, then you may define a scripts-win/ directory with a symmetrical set of scripts to whatever Unix scripts might be found in scripts/

To illustrate the above, suppose you have this bash script configured as "test/unit" in your package.json file and this bash script defined in scripts/test/unit:

#!/usr/bin/env bash

teenytest --helper test/unit-helper.js "lib/**/*.test.js"

In order to add Windows support, you could define scripts-win/test/unit.cmd with this script:

@ECHO OFF

teenytest --helper test\unit-helper.js "lib\**\*.test.js"

With a configuration like the above, if npm run test:unit is run from a Unix platform, the initial bash script in scripts/ will run. If the same CLI command is run from Windows, however, the batch script in scripts-win/ will be run.

Specifying custom script directories

By default, scripty will search for scripts in scripts/ relative to your module root (and if you're running windows, it'll check scripts-win/ first). If you'd like to customize the base directories scripty uses to search for your scripts, add a "scripty" object property to your package.json like so:

"config": {
  "scripty": {
    "path": "../core/scripts",
    "windowsPath": "../core/scripts-win"
  }
}

You can configure either or both of "path" and "windowsPath" to custom locations of your choosing. This may be handy in situations where multiple projects share the same set of scripts.

Sharing scripts via node modules

You can configure scripty to include certain node modules into its executable search space. This is beneficial if you would like to create a centralized place for your scripts and then share them across multiple projects. To include modules add a "scripty" object property, modules, to your package.json like so:

"config": {
  "scripty": {
    "modules": ["packageA", "packageB"]
  }
}

Each node module must contain a scripts directory. Below is an example directory structure:

root/
  scripts/
    foo
  node_modules/
    packageA/
      scripts/
        foo
        bar
    packageB/
      scripts/
        bar
        baz

In the above example the resolution of foo would resolve to root.scripts.foo. Local scripts take priority over ones defined in modules. The resolution of bar would resolve to root.node_modules.packageA.scripts.bar as packageA was the first module defined in the scripty.modules config.

Dry runs

To perform a dry run of your scripts—something that's handy to check which scripts will run from a particular command without actually executing potentially destructive scripts, you can set an environment variable like so:

$ SCRIPTY_DRY_RUN=true npm run publish:danger:stuff

This will print the path and contents of each script the command would execute in the order they would be executed if you were to run the command normally.

Worth mentioning, like all options this can be set in package.json under a "scripty" entry:

"config": {
  "scripty": {
    "dryRun": true
  }
}

Log output

Scripty is now quieter by default. The output can be configured to a level of verbose, info, warn, or error. Any logs equal to or higher than the setting are shown. All logs are printed to STDERR (to aid in redirection and piping).

$ SCRIPTY_LOG_LEVEL=verbose npm run publish:danger:stuff

This will print the path and contents of each script the command executes.

If you always want scripty to run your scripts at a certain level, you can set it in your package.json under a "scripty" entry:

"config": {
  "scripty": {
    "logLevel": "warn"
  }
}

SCRIPTY_SILENT and SCRIPTY_QUIET are aliases for SCRIPTY_LOG_LEVEL=silent SCRIPTY_VERBOSE is an alias for SCRIPTY_LOG_LEVEL=verbose (also "silent": true, etc in package.json#scripty)

SCRIPTY_DRY_RUN=true implies log level info

Explicit setting from logLevel takes precedence; otherwise, conflicting values between silent/verbose/dryRun will respect the highest level. If no setting is provided, scripty will infer its log level from npm's log level.

Likely questions

  • Is this pure magic? - Nope! For once, instilling some convention didn't require any clever metaprogramming, just environment variables npm already sets; try running printenv from a script some time!

  • Why isn't my script executing? - If your script isn't executing, make sure it's executable! In UNIX, this can be accomplished by running chmod +x scripts/path/to/my/script (permissions will also be stored in git)

  • How can I expect my users to understand what this does? Documenting your project's use of scripty in the README is probably a good idea. Here's some copy pasta if you don't feel like writing it up yourself:

    npm scripts

    MyProject uses scripty to organize npm scripts. The scripts are defined in the scripts directory. In package.json you'll see the word scripty as opposed to the script content you'd expect. For more info, see scripty's GitHub.

    {{ insert table containing script names and what they do, e.g. this }}

Code of Conduct

This project follows Test Double's code of conduct for all community interactions, including (but not limited to) one-on-one communications, public posts/comments, code reviews, pull requests, and GitHub issues. If violations occur, Test Double will take any action they deem appropriate for the infraction, up to and including blocking a user from the organization's repositories.

More Repositories

1

standard

🌟 Ruby Style Guide, with linter & automatic code fixer
Ruby
2,104
star
2

testdouble.js

A minimal test double library for TDD with JavaScript
JavaScript
1,407
star
3

suture

🏥 A Ruby gem that helps you refactor your legacy code
Ruby
1,401
star
4

contributing-tests

1,104
star
5

test-smells

A workbook repository of example test smells and what to do about them.
JavaScript
421
star
6

jasmine-rails

A Jasmine runner for rails projects that's got you covered in both the terminal and the browser
JavaScript
378
star
7

referral

🕵️‍♀️ Find, filter, and sort your Ruby code's definitions & references
Ruby
343
star
8

cypress-rails

Helps you write Cypress tests of your Rails app
Ruby
312
star
9

good-migrations

Prevent Rails from auto-loading app/ code when running database migrations
Ruby
294
star
10

mocktail

🥃 Take your Ruby, and make it a double!
Ruby
273
star
11

static-rails

Build & serve static sites (e.g. Jekyll, Hugo) from your Rails app
Ruby
149
star
12

maybe_later

Run code after the current Rack response or Rails action completes
Ruby
132
star
13

time_up

⏱ Create and manage multiple timers to tell where your Ruby code's time is going
Ruby
117
star
14

teenytest

A very simple, zero-config test runner for Node.js
JavaScript
97
star
15

test_data

A fast & reliable system for managing your Rails application's test data
Ruby
95
star
16

put

Ruby
92
star
17

theredoc

Makes your multi-line JavaScript strings look good
JavaScript
79
star
18

quibble

Makes it easy to replace require'd dependencies.
JavaScript
78
star
19

react-decoupler

JavaScript
55
star
20

noncommittal

A gem that ensures test isolation by preventing your Rails tests from committing to the database
Ruby
46
star
21

real-world-testing-video

testdouble/real-world-testing + screencasts
JavaScript
40
star
22

clojurescript.csv

A ClojureScript library for reading and writing CSV
Clojure
37
star
23

testdouble-jest

A testdouble.js extension to add support for Jest module mocking
JavaScript
37
star
24

grunt-markdown-blog

Grunt task for building a blog with markdown posts & underscore templates
CoffeeScript
36
star
25

ought

A dumb assertion library with smart diffs for JavaScript
JavaScript
34
star
26

cypress-capybara

Capybara finders re-implemented as custom Cypress commands
JavaScript
33
star
27

minitest-suite

Re-order your Minitest suite into logical sub-suites/groups
Ruby
32
star
28

rust-ffi-example

An example project that shows how to use FFI between Rust and Unity.
Rust
31
star
29

gem_dating

How old is that anyway?
Ruby
29
star
30

rspec-graphql_response

Verify ruby-graphql responses with a :graphql spec type
Ruby
25
star
31

ecto_resource

A simple module to clear up the boilerplate of CRUD resources in Phoenix context files.
Elixir
22
star
32

java-testing-example

An example project that's configured for JUnit and Mocha
Java
20
star
33

real-world-testing

Workshop for Testing JavaScripts
JavaScript
17
star
34

unusual-spending

A code kata for outside-in TDD in Node.js
JavaScript
16
star
35

webpacker-assets-demo

A demo repo to show how to reference images and styles when using Webpacker instead of Sprockets
Ruby
13
star
36

javascript-testing-tactics

The Missing Manual for writing great JavaScript Testing
13
star
37

magic_email_demo

An example Rails app that implements passwordless authentication by emailing a magic link
Ruby
12
star
38

scheduled-merge

Merge PRs on a specified date using Labels
JavaScript
12
star
39

rust-ffi-complex-example

Follow-up project to shows how to use complex data structures between Unity and Rust.
Rust
12
star
40

todos

JavaScript
11
star
41

grunt-asset-fingerprint

CoffeeScript
9
star
42

covet

Instruct a remote Express app to stub APIs via HTTP requests
CoffeeScript
9
star
43

bored

Gives you ideas of stuff to do when you're bored
Ruby
8
star
44

rails-twitter-oauth-example

An example Rails app that implements log in to Twitter via OAuth
Ruby
8
star
45

javascript-tdd-examples

Yet another little toy repo of javascript tdd examples
JavaScript
8
star
46

baizen

BAI file format parser
Clojure
8
star
47

tiny_type

Fast, easy, and simple runtime type checking for Ruby
Ruby
8
star
48

halfpipe

A Pipedrive client for Ruby that doesn't do half of what you want it to 🛹
Ruby
7
star
49

forewarn

Configure method invocation warnings for deprecated or dangerous methods (e.g. mutable methods in default-frozen String literals in Ruby 3)
Ruby
7
star
50

grunt-jasmine-bundle

A "spec" grunt task for Jasmine that includes a standard pack of helpers (jasmine-given, jasmine-stealth, jasmine-only). Uses minijasminenode.
CoffeeScript
6
star
51

servme

gimme for integration tests
Ruby
6
star
52

intro-to-node

Introduction to Node.js Workshop
JavaScript
6
star
53

standardrb

You're probably in the wrong place. This is an alias for the gem standard, whose binary is standardrb
Ruby
6
star
54

bootboot-example

An example of using boot-boot.
Ruby
5
star
55

testdrivennode

Test Driven Node.js Precompiler for Codemash 2014
JavaScript
5
star
56

docunit

Makes sure the code examples in your docs actually work
CoffeeScript
5
star
57

railsconf-test-drive-javascript

JavaScript
5
star
58

json-to-svg-to-pdf

Converts JSON/CSON input through SVG templates and renders them to PDF using librsvg
JavaScript
5
star
59

imagemagick-macos-font-setup

Sets up user fonts for imagemagick on macOS
Shell
5
star
60

jasmine-before-all

Adds a done-friendly beforeAll global function to Jasmine
JavaScript
5
star
61

good-day

An example ember + active_model_serializers + rails + lineman app
JavaScript
5
star
62

sockem

A wrapper around the ActionCable JS client to ensure eventual delivery for requests
Ruby
5
star
63

satisfaction

Satisfaction tracker for your work!
Ruby
5
star
64

headerify

Browserify plugin to add a comment containing lib name, version, description, and homepage to the top of the bundle
JavaScript
4
star
65

SublimeLinter-contrib-standardrb

SublimeLinter 3 plugin for Ruby, using Standard, a wrapper for Rubocop.
Python
4
star
66

rails-upsert-all-demo

An example app that demos use of Rails 6 `upsert_all` method
Ruby
4
star
67

cobbler

A tool to generate résumés for Test Double agents.
JavaScript
3
star
68

react-d3-blog-example

Example for Blog Post
JavaScript
3
star
69

supertitle

Converts between subtitles and transcript formats
Ruby
3
star
70

time_traveler_demo

A Rails app that demoes time traveling both Ruby and Postgres in lock-step with one another
Ruby
3
star
71

devops-standards

Standard Auditing Tools for DevSecOps best practices
Python
3
star
72

least

A pager that can dynamically filter log lines
Ruby
3
star
73

defuse

An API to define and use JavaScript in a module-y way. And nothing else.
JavaScript
3
star
74

lockify

Ensure an async function does not run concurrently.
JavaScript
3
star
75

jasmine-matcher-wrapper

A utility to wrap Jasmine 1.x argument matchers for use under Jasmine 2.x
CoffeeScript
3
star
76

testdouble-nock

JavaScript
3
star
77

teenytest-promise

Promise support for asynchronous teenytest tests
JavaScript
3
star
78

npm-tree

Generates a tree of all the node.js modules depended on by a module
CoffeeScript
3
star
79

function-names-at-line

Name the functions found at a particular line number in some JavaScript source
JavaScript
2
star
80

tradecraft

CSS
2
star
81

course-cypress-intro-demo-app

Demo application to supplement Test Double's End-to-end Testing with Cypress intro video course
Ruby
2
star
82

standard-ruby-action

Ruby
2
star
83

rails-training-201

A demo app for Rails 201 students to build on!
Ruby
2
star
84

testdrivennode-frontend

JavaScript
2
star
85

yslow-grader

A little Node.js wrapper for YSlow for PhantomJS
CoffeeScript
2
star
86

ios-learnins

Objective-C
2
star
87

fetcher

Fetches things based on a JSON recipe hosted in a repository
CoffeeScript
2
star
88

backbone-fixins

Boilerplate that strengthens your backbone
JavaScript
2
star
89

ruby_rails_training_github

Ruby
1
star
90

prioritize-api

Elixir
1
star
91

baruco2014-angular

Ruby
1
star
92

oredev2014-angular

JavaScript
1
star
93

double-up

Slack scheduler to set up rotating brunch pairings
Ruby
1
star
94

elm-testdouble

A minimal test double library for TDD with Elm
Elm
1
star
95

doubot

test double's hubot
CoffeeScript
1
star
96

jasmine-example

JavaScript
1
star
97

arg-that

arg-that makes it easier to assert equality on complex objects
Ruby
1
star
98

react-routing-example

Example for screencast on client-side routing in React
CSS
1
star
99

cucumber-peel

Provides a CLI to search a project's step implementations for a given step
Ruby
1
star
100

test_rails_app

A starter Rails application to test your environment setup
Ruby
1
star