• Stars
    star
    963
  • Rank 47,492 (Top 1.0 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated over 1 year 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,416
star
3

suture

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

contributing-tests

1,112
star
5

test-smells

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

jasmine-rails

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

referral

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

cypress-rails

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

good-migrations

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

mocktail

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

static-rails

Build & serve static sites (e.g. Jekyll, Hugo) from your Rails app
Ruby
151
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

test_data

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

teenytest

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

put

Ruby
95
star
17

quibble

Makes it easy to replace require'd dependencies.
JavaScript
94
star
18

theredoc

Makes your multi-line JavaScript strings look good
JavaScript
80
star
19

react-decoupler

JavaScript
56
star
20

noncommittal

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

real-world-testing-video

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

testdouble-jest

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

clojurescript.csv

A ClojureScript library for reading and writing CSV
Clojure
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
30
star
30

azure-blob

Azure blob client and Active Storage adapter.
Ruby
29
star
31

rspec-graphql_response

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

ecto_resource

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

java-testing-example

An example project that's configured for JUnit and Mocha
Java
21
star
34

real-world-testing

Workshop for Testing JavaScripts
JavaScript
17
star
35

unusual-spending

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

moderate_parameters

Moderate Parameters Gem
Ruby
16
star
37

magic_email_demo

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

webpacker-assets-demo

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

rust-ffi-complex-example

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

javascript-testing-tactics

The Missing Manual for writing great JavaScript Testing
13
star
41

scheduled-merge

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

todos

JavaScript
11
star
43

grunt-asset-fingerprint

CoffeeScript
9
star
44

covet

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

rails-twitter-oauth-example

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

baizen

BAI file format parser
Clojure
8
star
47

javascript-tdd-examples

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

bored

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

tiny_type

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

halfpipe

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

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
52

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
53

servme

gimme for integration tests
Ruby
6
star
54

intro-to-node

Introduction to Node.js Workshop
JavaScript
6
star
55

standardrb

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

bootboot-example

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

testdrivennode

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

docunit

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

railsconf-test-drive-javascript

JavaScript
5
star
60

json-to-svg-to-pdf

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

jasmine-before-all

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

imagemagick-macos-font-setup

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

good-day

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

sockem

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

satisfaction

Satisfaction tracker for your work!
Ruby
5
star
66

headerify

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

SublimeLinter-contrib-standardrb

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

rails-upsert-all-demo

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

cobbler

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

supertitle

Converts between subtitles and transcript formats
Ruby
3
star
71

time_traveler_demo

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

least

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

devops-standards

Standard Auditing Tools for DevSecOps best practices
Python
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

defuse

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

testdouble-nock

JavaScript
3
star
78

react-d3-blog-example

Example for Blog Post
JavaScript
3
star
79

teenytest-promise

Promise support for asynchronous teenytest tests
JavaScript
3
star
80

npm-tree

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

function-names-at-line

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

tradecraft

CSS
2
star
83

standard-ruby-action

Ruby
2
star
84

rails-training-201

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

course-cypress-intro-demo-app

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

testdrivennode-frontend

JavaScript
2
star
87

yslow-grader

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

ios-learnins

Objective-C
2
star
89

fetcher

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

backbone-fixins

Boilerplate that strengthens your backbone
JavaScript
2
star
91

ruby_rails_training_github

Ruby
1
star
92

prioritize-api

Elixir
1
star
93

baruco2014-angular

Ruby
1
star
94

jasmine-example

JavaScript
1
star
95

oredev2014-angular

JavaScript
1
star
96

double-up

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

elm-testdouble

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

doubot

test double's hubot
CoffeeScript
1
star
99

arg-that

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

cucumber-peel

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