fix: update all packages, tests, and README

This commit is contained in:
Kent C. Dodds
2019-10-01 10:50:59 -06:00
parent dcc63c53bc
commit 83db27a819
17 changed files with 276 additions and 296 deletions
-5
View File
@@ -18,13 +18,10 @@ learn how: http://kcd.im/pull-request
Relevant code or config
```javascript
```
What you did:
What happened:
<!-- Please provide the full error message/screenshots/anything -->
@@ -38,6 +35,4 @@ minimal amount of code possible.
Problem description:
Suggested solution:
+8 -2
View File
@@ -15,21 +15,27 @@ merge of your pull request!
-->
<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**:
<!-- Why are these changes necessary? -->
**Why**:
<!-- How were these changes implemented? -->
**How**:
<!-- Have you done all of these things? -->
**Checklist**:
<!-- add "N/A" to the end of each line that's irrelevant to your changes -->
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
- [ ] Documentation
- [ ] Tests
- [ ] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
- [ ] Added myself to contributors table <!-- this is optional, see the contributing guidelines for instructions -->
- [ ] Ready to be merged
<!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
<!-- feel free to add additional comments -->
+3 -2
View File
@@ -1,4 +1,5 @@
# CHANGELOG
The changelog is automatically updated using [semantic-release](https://github.com/semantic-release/semantic-release).
You can see it on the [releases page](../../releases).
The changelog is automatically updated using
[semantic-release](https://github.com/semantic-release/semantic-release). You
can see it on the [releases page](../../releases).
+11 -44
View File
@@ -2,14 +2,14 @@
Thanks for being willing to contribute!
**Working on your first Pull Request?** You can learn how from this *free* series
[How to Contribute to an Open Source Project on GitHub][egghead]
**Working on your first Pull Request?** You can learn how from this _free_
series [How to Contribute to an Open Source Project on GitHub][egghead]
## Project setup
1. Fork and clone the repo
2. `$ npm install` to install dependencies
3. `$ npm run validate` to validate you've got it working
2. `npm install` to install dependencies
3. `npm run validate` to validate you've got it working
4. Create a branch for your PR
> Tip: Keep your `master` branch pointing at the original repository and make
@@ -21,45 +21,11 @@ Thanks for being willing to contribute!
> git branch --set-upstream-to=upstream/master master
> ```
>
> This will add the original repository as a "remote" called "upstream,"
> Then fetch the git information from that remote, then set your local `master`
> branch to use the upstream master branch whenever you run `git pull`.
> Then you can make all of your pull request branches based on this `master`
> branch. Whenever you want to update your version of `master`, do a regular
> `git pull`.
## Add yourself as a contributor
This project follows the [all contributors][all-contributors] specification.
To add yourself to the table of contributors on the `README.md`, please use the
automated script as part of your PR:
```console
npm run add-contributor
```
Follow the prompt and commit `.all-contributorsrc` and `README.md` in the PR.
If you've already added yourself to the list and are making
a new type of contribution, you can run it again and select the added
contribution type.
## Committing and Pushing changes
Please make sure to run the tests before you commit your changes. You can run
`npm run test:update` which will update any snapshots that need updating.
Make sure to include those changes (if they exist) in your commit.
### opt into git hooks
There are git hooks set up with this project that are automatically installed
when you install dependencies. They're really handy, but are turned off by
default (so as to not hinder new contributors). You can opt into these by
creating a file called `.opt-in` at the root of the project and putting this
inside:
```
pre-commit
```
> This will add the original repository as a "remote" called "upstream," Then
> fetch the git information from that remote, then set your local `master`
> branch to use the upstream master branch whenever you run `git pull`. Then you
> can make all of your pull request branches based on this `master` branch.
> Whenever you want to update your version of `master`, do a regular `git pull`.
## Help needed
@@ -68,6 +34,7 @@ Please checkout the [the open issues][issues]
Also, please watch the repo and respond to questions/bug reports/feature
requests! Thanks!
[egghead]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
[egghead]:
https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
[all-contributors]: https://github.com/kentcdodds/all-contributors
[issues]: https://github.com/kentcdodds/cross-env/issues
+68 -60
View File
@@ -1,3 +1,20 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [cross-env 🔀](#cross-env-)
- [The problem](#the-problem)
- [This solution](#this-solution)
- [Installation](#installation)
- [Usage](#usage)
- [`cross-env` vs `cross-env-shell`](#cross-env-vs-cross-env-shell)
- [Windows Issues](#windows-issues)
- [Inspiration](#inspiration)
- [Other Solutions](#other-solutions)
- [Contributors](#contributors)
- [LICENSE](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<p align="center">
<a href="https://codefund.io/properties/445/visit-sponsor">
<img src="https://codefund.io/properties/445/sponsor" />
@@ -16,22 +33,11 @@ Run scripts that set and use environment variables across platforms
[![Travis Build Status][build-badge]][build]
[![AppVeyor Build Status][win-build-badge]][win-build]
[![Code Coverage][coverage-badge]][coverage]
[![Dependencies][dependencyci-badge]][dependencyci]
[![version][version-badge]][package]
[![node-version][node-version-badge]][node]
[![downloads][downloads-badge]][npm-stat]
[![version][version-badge]][package] [![MIT License][license-badge]][license]
[![MIT License][license-badge]][LICENSE]
[![All Contributors](https://img.shields.io/badge/all_contributors-20-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Donate][donate-badge]][donate]
[![Code of Conduct][coc-badge]][coc]
[![Roadmap][roadmap-badge]][roadmap]
[![Examples][examples-badge]][examples]
[![Watch on GitHub][github-watch-badge]][github-watch]
[![Star on GitHub][github-star-badge]][github-star]
[![Tweet][twitter-badge]][twitter]
[![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc]
[![downloads][downloads-badge]][npmtrends]
## The problem
@@ -60,8 +66,8 @@ npm install --save-dev cross-env
> WARNING! Make sure that when you're installing packages that you spell things
> correctly to avoid [mistakenly installing malware][malware]
> NOTE : Version 6 of cross-env only supports Node.js 8 and higher, to use it on Node.js 7 or lower install version 5
> ```npm install --save-dev cross-env@5 ```
> NOTE : Version 6 of cross-env only supports Node.js 8 and higher, to use it on
> Node.js 7 or lower install version 5 `npm install --save-dev cross-env@5`
## Usage
@@ -100,12 +106,16 @@ Where `childScript` holds the actual command to execute and `parentScript` sets
the environment variables to use. Then instead of run the childScript you run
the parent. This is quite useful for launching the same command with different
env variables or when the environment variables are too long to have everything
in one line. It also means that you can use `$GREET` env var syntax even on
in one line. It also means that you can use `$GREET` env var syntax even on
Windows which would usually require it to be `%GREET%`.
If you precede a dollar sign with an odd number of backslashes the expression statement will not be replaced. Note that this means backslashes after the JSON string escaping took place. `"FOO=\\$BAR"` will not be replaced. `"FOO=\\\\$BAR"` will be replaced though.
If you precede a dollar sign with an odd number of backslashes the expression
statement will not be replaced. Note that this means backslashes after the JSON
string escaping took place. `"FOO=\\$BAR"` will not be replaced.
`"FOO=\\\\$BAR"` will be replaced though.
Lastly, if you want to pass a JSON string (e.g., when using [ts-loader]), you can do as follows:
Lastly, if you want to pass a JSON string (e.g., when using [ts-loader]), you
can do as follows:
```json
{
@@ -115,18 +125,18 @@ Lastly, if you want to pass a JSON string (e.g., when using [ts-loader]), you ca
}
```
Pay special attention to the **triple backslash** `(\\\)` **before** the **double quotes** `(")` and the **absence** of **single quotes** `(')`.
Both of these conditions have to be met in order to work both on Windows and UNIX.
Pay special attention to the **triple backslash** `(\\\)` **before** the
**double quotes** `(")` and the **absence** of **single quotes** `(')`. Both of
these conditions have to be met in order to work both on Windows and UNIX.
## `cross-env` vs `cross-env-shell`
The `cross-env` module exposes two bins: `cross-env` and `cross-env-shell`. The
first one executes commands using [`cross-spawn`][cross-spawn], while the
second one uses the `shell` option from Node's `spawn`.
first one executes commands using [`cross-spawn`][cross-spawn], while the second
one uses the `shell` option from Node's `spawn`.
The main use case for `cross-env-shell` is when you need an environment
variable to be set across an entire inline shell script, rather than just one
command.
The main use case for `cross-env-shell` is when you need an environment variable
to be set across an entire inline shell script, rather than just one command.
For example, if you want to have the environment variable apply to several
commands in series then you will need to wrap those in quotes and use
@@ -140,29 +150,34 @@ commands in series then you will need to wrap those in quotes and use
}
```
The rule of thumb is: if you want to pass to `cross-env` a command that
contains special shell characters *that you want interpreted*, then use
The rule of thumb is: if you want to pass to `cross-env` a command that contains
special shell characters _that you want interpreted_, then use
`cross-env-shell`. Otherwise stick to `cross-env`.
On Windows you need to use `cross-env-shell`, if you want to handle [signal events](https://nodejs.org/api/process.html#process_signal_events) inside of your program. A common case for that is when you want to capture a `SIGINT` event invoked by pressing `Ctrl + C` on the command-line interface.
On Windows you need to use `cross-env-shell`, if you want to handle
[signal events](https://nodejs.org/api/process.html#process_signal_events)
inside of your program. A common case for that is when you want to capture a
`SIGINT` event invoked by pressing `Ctrl + C` on the command-line interface.
## Windows Issues
Please note that `npm` uses `cmd` by default and that doesn't support command
substitution, so if you want to leaverage that, then you need to update your
substitution, so if you want to leverage that, then you need to update your
`.npmrc` to set the `script-shell` to powershell.
[Learn more here](https://github.com/kentcdodds/cross-env/issues/192#issuecomment-513341729).
## Inspiration
I originally created this to solve a problem I was having with my npm scripts in
[angular-formly][angular-formly]. This made contributing to the project
much easier for Windows users.
[angular-formly][angular-formly]. This made contributing to the project much
easier for Windows users.
## Other Solutions
- [`env-cmd`](https://github.com/toddbluhm/env-cmd) - Reads environment variables from a file instead
- [`@naholyr/cross-env`](https://www.npmjs.com/package/@naholyr/cross-env) - `cross-env` with support for setting default values
- [`env-cmd`](https://github.com/toddbluhm/env-cmd) - Reads environment
variables from a file instead
- [`@naholyr/cross-env`](https://www.npmjs.com/package/@naholyr/cross-env) -
`cross-env` with support for setting default values
## Contributors
@@ -201,11 +216,12 @@ Thanks goes to these people ([emoji key][emojis]):
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors][all-contributors] specification. Contributions of any kind welcome!
This project follows the [all-contributors][all-contributors] specification.
Contributions of any kind welcome!
> Note: this was added late into the project. If you've contributed to this
> project in any way, please make a pull request to add yourself to the list
> by following the instructions in the `CONTRIBUTING.md`
> project in any way, please make a pull request to add yourself to the list by
> following the instructions in the `CONTRIBUTING.md`
## LICENSE
@@ -213,41 +229,33 @@ MIT
[npm]: https://www.npmjs.com/
[node]: https://nodejs.org
[build-badge]: https://img.shields.io/travis/kentcdodds/cross-env.svg?style=flat-square
[build-badge]:
https://img.shields.io/travis/kentcdodds/cross-env.svg?style=flat-square
[build]: https://travis-ci.org/kentcdodds/cross-env
[win-build-badge]: https://img.shields.io/appveyor/ci/kentcdodds/cross-env.svg?style=flat-square
[win-build-badge]:
https://img.shields.io/appveyor/ci/kentcdodds/cross-env.svg?style=flat-square
[win-build]: https://ci.appveyor.com/project/kentcdodds/cross-env
[coverage-badge]: https://img.shields.io/codecov/c/github/kentcdodds/cross-env.svg?style=flat-square
[coverage-badge]:
https://img.shields.io/codecov/c/github/kentcdodds/cross-env.svg?style=flat-square
[coverage]: https://codecov.io/github/kentcdodds/cross-env
[dependencyci-badge]: https://dependencyci.com/github/kentcdodds/cross-env/badge?style=flat-square
[dependencyci]: https://dependencyci.com/github/kentcdodds/cross-env
[version-badge]: https://img.shields.io/npm/v/cross-env.svg?style=flat-square
[package]: https://www.npmjs.com/package/cross-env
[node-version-badge]: https://img.shields.io/badge/node-%3E%3D%204.0-orange.svg?style=flat-square
[downloads-badge]: https://img.shields.io/npm/dm/cross-env.svg?style=flat-square
[npm-stat]: http://npm-stat.com/charts.html?package=cross-env&from=2016-04-01
[npmtrends]: https://www.npmtrends.com/cross-env
[license-badge]: https://img.shields.io/npm/l/cross-env.svg?style=flat-square
[license]: https://github.com/kentcdodds/cross-env/blob/master/other/LICENSE
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs-badge]:
https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs]: http://makeapullrequest.com
[donate-badge]: https://img.shields.io/badge/$-support-green.svg?style=flat-square
[donate]: http://kcd.im/donate
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]: https://github.com/kentcdodds/cross-env/blob/master/other/CODE_OF_CONDUCT.md
[roadmap-badge]: https://img.shields.io/badge/%F0%9F%93%94-roadmap-CD9523.svg?style=flat-square
[roadmap]: https://github.com/kentcdodds/cross-env/blob/master/other/ROADMAP.md
[examples-badge]: https://img.shields.io/badge/%F0%9F%92%A1-examples-8C8E93.svg?style=flat-square
[examples]: https://github.com/kentcdodds/cross-env/blob/master/other/EXAMPLES.md
[github-watch-badge]: https://img.shields.io/github/watchers/kentcdodds/cross-env.svg?style=social
[github-watch]: https://github.com/kentcdodds/cross-env/watchers
[github-star-badge]: https://img.shields.io/github/stars/kentcdodds/cross-env.svg?style=social
[github-star]: https://github.com/kentcdodds/cross-env/stargazers
[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20cross-env!%20https://github.com/kentcdodds/cross-env%20%F0%9F%91%8D
[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/kentcdodds/cross-env.svg?style=social
[coc-badge]:
https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]:
https://github.com/kentcdodds/cross-env/blob/master/other/CODE_OF_CONDUCT.md
[emojis]: https://github.com/kentcdodds/all-contributors#emoji-key
[all-contributors]: https://github.com/kentcdodds/all-contributors
[win-bash]: https://msdn.microsoft.com/en-us/commandline/wsl/about
[angular-formly]: https://github.com/formly-js/angular-formly
[cross-spawn]: https://www.npmjs.com/package/cross-spawn
[ts-loader]: https://www.npmjs.com/package/ts-loader
[malware]: http://blog.npmjs.org/post/163723642530/crossenv-malware-on-the-npm-registry
[malware]:
http://blog.npmjs.org/post/163723642530/crossenv-malware-on-the-npm-registry
-17
View File
@@ -1,17 +0,0 @@
const __mock = {
reset() {
__mock.spawned = null
Object.assign(module.exports, {
__mock,
spawn: jest.fn(() => {
__mock.spawned = {
on: jest.fn(),
kill: jest.fn(),
}
return __mock.spawned
}),
})
},
}
__mock.reset()
+1 -1
View File
@@ -1,6 +1,6 @@
const jestConfig = require('kcd-scripts/config').jest
jestConfig.coveragePathIgnorePatterns = jestConfig.coveragePathIgnorePatterns.concat(
['/bin/']
['/bin/'],
)
module.exports = jestConfig
+24 -23
View File
@@ -5,30 +5,30 @@
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual identity
and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
@@ -37,11 +37,11 @@ Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, or to ban temporarily or permanently any
contributor for other behaviors that they deem inappropriate, threatening,
offensive, or harmful.
## Scope
@@ -58,8 +58,9 @@ Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at kent+coc@doddsfamily.us. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
obligated to maintain confidentiality with regard to the reporter of an
incident. Further details of specific enforcement policies may be posted
separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
@@ -67,8 +68,8 @@ members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+22 -10
View File
@@ -1,8 +1,7 @@
{
"name": "cross-env",
"version": "0.0.0-semantically-released",
"description":
"Run scripts that set and use environment variables across platforms",
"description": "Run scripts that set and use environment variables across platforms",
"main": "dist/index.js",
"bin": {
"cross-env": "dist/bin/cross-env.js",
@@ -12,28 +11,41 @@
"node": ">=8.0"
},
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "kcd-scripts build",
"lint": "kcd-scripts lint",
"test": "kcd-scripts test",
"test:update": "npm test -- --updateSnapshot --coverage",
"validate": "kcd-scripts validate",
"precommit": "kcd-scripts precommit"
"validate": "kcd-scripts validate"
},
"files": ["dist"],
"keywords": ["cross-environment", "environment variable", "windows"],
"husky": {
"hooks": {
"pre-commit": "kcd-scripts pre-commit"
}
},
"files": [
"dist"
],
"keywords": [
"cross-environment",
"environment variable",
"windows"
],
"author": "Kent C. Dodds <[email protected]> (http://kentcdodds.com/)",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.6.2",
"cross-spawn": "^7.0.0"
},
"devDependencies": {
"kcd-scripts": "^0.3.4"
"kcd-scripts": "^1.8.0"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js"
},
"eslintIgnore": ["node_modules", "coverage", "dist"],
"eslintIgnore": [
"node_modules",
"coverage",
"dist"
],
"repository": {
"type": "git",
"url": "https://github.com/kentcdodds/cross-env.git"
+1
View File
@@ -0,0 +1 @@
module.exports = require('kcd-scripts/prettier')
-12
View File
@@ -1,12 +0,0 @@
const __mock = {
reset() {
Object.assign(__mock, {returnValue: false})
},
}
__mock.reset()
module.exports = function isWindowsMock() {
return __mock.returnValue
}
Object.assign(module.exports, {__mock})
+20 -15
View File
@@ -8,15 +8,16 @@ const env = {
test1: 'b',
test2: 'c',
test3: 'd',
'empty_var': ''
// eslint-disable-next-line babel/camelcase
empty_var: '',
}
beforeEach(() => {
isWindowsMock.__mock.reset()
afterEach(() => {
jest.clearAllMocks()
})
test(`converts unix-style env variable usage for windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(commandConvert('$test', env)).toBe('%test%')
})
@@ -25,51 +26,55 @@ test(`leaves command unchanged when not a variable`, () => {
})
test(`doesn't convert windows-style env variable`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(commandConvert('%test%', env)).toBe('%test%')
})
test(`leaves variable unchanged when using correct operating system`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(commandConvert('$test', env)).toBe('$test')
})
test(`is stateless`, () => {
// this test prevents falling into regexp traps like this:
// http://stackoverflow.com/a/1520853/971592
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(commandConvert('$test', env)).toBe(commandConvert('$test', env))
})
test(`converts embedded unix-style env variables usage for windows`, () => {
isWindowsMock.__mock.returnValue = true
expect(commandConvert('$test1/$test2/$test3', env)).toBe('%test1%/%test2%/%test3%')
isWindowsMock.mockReturnValue(true)
expect(commandConvert('$test1/$test2/$test3', env)).toBe(
'%test1%/%test2%/%test3%',
)
})
// eslint-disable-next-line max-len
test(`leaves embedded variables unchanged when using correct operating system`, () => {
isWindowsMock.__mock.returnValue = false
expect(commandConvert('$test1/$test2/$test3', env)).toBe('$test1/$test2/$test3')
isWindowsMock.mockReturnValue(false)
expect(commandConvert('$test1/$test2/$test3', env)).toBe(
'$test1/$test2/$test3',
)
})
test(`converts braced unix-style env variable usage for windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
// eslint-disable-next-line no-template-curly-in-string
expect(commandConvert('${test}', env)).toBe('%test%')
})
test(`removes non-existent variables from the converted command`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(commandConvert('$test1/$foo/$test2', env)).toBe('%test1%//%test2%')
})
test(`removes empty variables from the converted command`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(commandConvert('$foo/$test/$empty_var', env)).toBe('/%test%/')
})
test(`normalizes command on windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
// index.js calls `commandConvert` with `normalize` param
// as `true` for command only
expect(commandConvert('./cmd.bat', env, true)).toBe('cmd.bat')
+71 -74
View File
@@ -2,24 +2,33 @@ import crossSpawnMock from 'cross-spawn'
import isWindowsMock from '../is-windows'
jest.mock('../is-windows')
jest.mock('cross-spawn')
const crossEnv = require('../')
const getSpawned = (call = 0) => crossSpawnMock.spawn.mock.results[call].value
process.setMaxListeners(20)
beforeEach(() => {
crossSpawnMock.__mock.reset()
jest.spyOn(process, 'exit').mockImplementation(() => {})
crossSpawnMock.spawn.mockReturnValue({on: jest.fn(), kill: jest.fn()})
})
it(`should set environment variables and run the remaining command`, () => {
afterEach(() => {
jest.clearAllMocks()
process.exit.mockRestore()
})
test(`sets environment variables and run the remaining command`, () => {
testEnvSetting({FOO_ENV: 'production'}, 'FOO_ENV=production')
})
it(`should APPDATA be undefined and not string`, () => {
test(`APPDATA is undefined and not string`, () => {
testEnvSetting({FOO_ENV: 'production', APPDATA: 2}, 'FOO_ENV=production')
})
it(`should handle multiple env variables`, () => {
test(`handles multiple env variables`, () => {
testEnvSetting(
{
FOO_ENV: 'production',
@@ -32,35 +41,35 @@ it(`should handle multiple env variables`, () => {
)
})
it(`should handle special characters`, () => {
test(`handles special characters`, () => {
testEnvSetting({FOO_ENV: './!?'}, 'FOO_ENV=./!?')
})
it(`should handle single-quoted strings`, () => {
test(`handles single-quoted strings`, () => {
testEnvSetting({FOO_ENV: 'bar env'}, "FOO_ENV='bar env'")
})
it(`should handle double-quoted strings`, () => {
test(`handles double-quoted strings`, () => {
testEnvSetting({FOO_ENV: 'bar env'}, 'FOO_ENV="bar env"')
})
it(`should handle equality signs in quoted strings`, () => {
test(`handles equality signs in quoted strings`, () => {
testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
})
it(`should handle empty single-quoted strings`, () => {
test(`handles empty single-quoted strings`, () => {
testEnvSetting({FOO_ENV: ''}, "FOO_ENV=''")
})
it(`should handle empty double-quoted strings`, () => {
test(`handles empty double-quoted strings`, () => {
testEnvSetting({FOO_ENV: ''}, 'FOO_ENV=""')
})
it(`should handle no value after the equals sign`, () => {
test(`handles no value after the equals sign`, () => {
testEnvSetting({FOO_ENV: ''}, 'FOO_ENV=')
})
it(`should handle quoted scripts`, () => {
test(`handles quoted scripts`, () => {
crossEnv(['GREETING=Hi', 'NAME=Joe', 'echo $GREETING && echo $NAME'], {
shell: true,
})
@@ -70,15 +79,12 @@ it(`should handle quoted scripts`, () => {
{
stdio: 'inherit',
shell: true,
env: Object.assign({}, process.env, {
GREETING: 'Hi',
NAME: 'Joe',
}),
env: {...process.env, GREETING: 'Hi', NAME: 'Joe'},
},
)
})
it(`should handle escaped characters`, () => {
test(`handles escaped characters`, () => {
// this escapes \,",' and $
crossEnv(
['GREETING=Hi', 'NAME=Joe', 'echo \\"\\\'\\$GREETING\\\'\\" && echo $NAME'],
@@ -92,96 +98,88 @@ it(`should handle escaped characters`, () => {
{
stdio: 'inherit',
shell: true,
env: Object.assign({}, process.env, {
GREETING: 'Hi',
NAME: 'Joe',
}),
env: {...process.env, GREETING: 'Hi', NAME: 'Joe'},
},
)
})
it(`should do nothing given no command`, () => {
test(`does nothing when given no command`, () => {
crossEnv([])
expect(crossSpawnMock.spawn).toHaveBeenCalledTimes(0)
})
it(`should normalize command on windows`, () => {
isWindowsMock.__mock.returnValue = true
test(`normalizes commands on windows`, () => {
isWindowsMock.mockReturnValue(true)
crossEnv(['./cmd.bat'])
expect(crossSpawnMock.spawn).toHaveBeenCalledWith('cmd.bat', [], {
stdio: 'inherit',
env: Object.assign({}, process.env),
env: {...process.env},
})
isWindowsMock.__mock.reset()
})
it(`should not normalize command arguments on windows`, () => {
isWindowsMock.__mock.returnValue = true
test(`does not normalize command arguments on windows`, () => {
isWindowsMock.mockReturnValue(true)
crossEnv(['echo', 'http://example.com'])
expect(crossSpawnMock.spawn).toHaveBeenCalledWith(
'echo',
['http://example.com'],
{
stdio: 'inherit',
env: Object.assign({}, process.env),
env: {...process.env},
},
)
isWindowsMock.__mock.reset()
})
it(`should propagate kill signals`, () => {
test(`propagates kill signals`, () => {
testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
process.emit('SIGTERM')
process.emit('SIGINT')
process.emit('SIGHUP')
process.emit('SIGBREAK')
expect(crossSpawnMock.__mock.spawned.kill).toHaveBeenCalledWith('SIGTERM')
expect(crossSpawnMock.__mock.spawned.kill).toHaveBeenCalledWith('SIGINT')
expect(crossSpawnMock.__mock.spawned.kill).toHaveBeenCalledWith('SIGHUP')
expect(crossSpawnMock.__mock.spawned.kill).toHaveBeenCalledWith('SIGBREAK')
const spawned = getSpawned()
expect(spawned.kill).toHaveBeenCalledWith('SIGTERM')
expect(spawned.kill).toHaveBeenCalledWith('SIGINT')
expect(spawned.kill).toHaveBeenCalledWith('SIGHUP')
expect(spawned.kill).toHaveBeenCalledWith('SIGBREAK')
})
it(`should propagate unhandled exit signal`, () => {
process.exit = jest.fn()
testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = crossSpawnMock.__mock.spawned.on.mock.calls[0][1]
const spawnExitCode = null
spawnExitCallback(spawnExitCode)
expect(process.exit).toHaveBeenCalledWith(1)
})
it(`should exit cleanly with SIGINT with a null exit code`, () => {
process.exit = jest.fn()
testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = crossSpawnMock.__mock.spawned.on.mock.calls[0][1]
const spawnExitCode = null
const spawnExitSignal = 'SIGINT'
spawnExitCallback(spawnExitCode, spawnExitSignal)
expect(process.exit).toHaveBeenCalledWith(0)
})
it(`should propagate regular exit code`, () => {
process.exit = jest.fn()
testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = crossSpawnMock.__mock.spawned.on.mock.calls[0][1]
const spawnExitCode = 0
spawnExitCallback(spawnExitCode)
expect(process.exit).toHaveBeenCalledWith(0)
})
it(`should keep backslashes`, () => {
isWindowsMock.__mock.returnValue = true
test(`keeps backslashes`, () => {
isWindowsMock.mockReturnValue(true)
crossEnv(['echo', '\\\\\\\\someshare\\\\somefolder'])
expect(crossSpawnMock.spawn).toHaveBeenCalledWith(
'echo',
['\\\\someshare\\somefolder'],
{
stdio: 'inherit',
env: Object.assign({}, process.env),
env: {...process.env},
},
)
isWindowsMock.__mock.reset()
})
test(`propagates unhandled exit signal`, () => {
const {spawned} = testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = spawned.on.mock.calls[0][1]
const spawnExitCode = null
spawnExitCallback(spawnExitCode)
expect(process.exit).toHaveBeenCalledWith(1)
})
test(`exits cleanly with SIGINT with a null exit code`, () => {
const {spawned} = testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = spawned.on.mock.calls[0][1]
const spawnExitCode = null
const spawnExitSignal = 'SIGINT'
spawnExitCallback(spawnExitCode, spawnExitSignal)
expect(process.exit).toHaveBeenCalledWith(0)
})
test(`propagates regular exit code`, () => {
const {spawned} = testEnvSetting({FOO_ENV: 'foo=bar'}, 'FOO_ENV="foo=bar"')
const spawnExitCallback = spawned.on.mock.calls[0][1]
const spawnExitCode = 0
spawnExitCallback(spawnExitCode)
expect(process.exit).toHaveBeenCalledWith(0)
})
function testEnvSetting(expected, ...envSettings) {
@@ -200,17 +198,16 @@ function testEnvSetting(expected, ...envSettings) {
env.APPDATA = process.env.APPDATA
}
Object.assign(env, expected)
expect(ret).toBe(crossSpawnMock.__mock.spawned)
const spawned = getSpawned()
expect(ret).toBe(spawned)
expect(crossSpawnMock.spawn).toHaveBeenCalledTimes(1)
expect(crossSpawnMock.spawn).toHaveBeenCalledWith('echo', ['hello world'], {
stdio: 'inherit',
shell: undefined,
env: Object.assign({}, process.env, env),
env: {...process.env, ...env},
})
expect(crossSpawnMock.__mock.spawned.on).toHaveBeenCalledTimes(1)
expect(crossSpawnMock.__mock.spawned.on).toHaveBeenCalledWith(
'exit',
expect.any(Function),
)
expect(spawned.on).toHaveBeenCalledTimes(1)
expect(spawned.on).toHaveBeenCalledWith('exit', expect.any(Function))
return {spawned}
}
+21 -6
View File
@@ -1,17 +1,32 @@
import isWindows from "../is-windows"
import isWindows from '../is-windows'
it(`should return true if the current OS is Windows`, () => {
process.platform = 'win32'
expect(isWindows()).toBe(true)
const {
platform,
env: {OSTYPE},
} = process
// make the platform property writeable
Object.defineProperty(process, 'platform', {
value: platform,
writable: true,
})
it(`should return false if the current OS is not Windows`, () => {
afterEach(() => {
process.platform = platform
process.env.OSTYPE = OSTYPE
})
test(`returns true if the current OS is Windows`, () => {
process.platform = 'win32'
expect(isWindows()).toBe(true)
})
test(`returns false if the current OS is not Windows`, () => {
process.platform = 'linux'
expect(isWindows()).toBe(false)
})
it(`should return true if the OSTYPE is cygwin or msys`, () => {
test(`returns true if the OSTYPE is cygwin or msys`, () => {
process.platform = 'linux'
process.env.OSTYPE = 'cygwin'
+21 -21
View File
@@ -9,7 +9,6 @@ beforeEach(() => {
process.env.VAR1 = 'value1'
process.env.VAR2 = 'value2'
process.env.JSON_VAR = JSON_VALUE
isWindowsMock.__mock.reset()
})
afterEach(() => {
@@ -17,105 +16,106 @@ afterEach(() => {
delete env.VAR1
delete env.VAR2
delete env.JSON_VAR
jest.clearAllMocks()
})
test(`doesn't affect simple variable values`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo')).toBe('foo')
})
test(`doesn't convert a ; into a : on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('foo;bar', 'PATH')).toBe('foo;bar')
})
test(`doesn't convert a ; into a : for non-PATH on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('foo;bar', 'FOO')).toBe('foo;bar')
})
test(`doesn't convert a ; into a : for non-PATH on Windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo;bar', 'FOO')).toBe('foo;bar')
})
test(`converts a : into a ; on Windows if PATH`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo:bar', 'PATH')).toBe('foo;bar')
})
test(`doesn't convert already valid separators`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('foo:bar')).toBe('foo:bar')
})
test(`doesn't convert escaped separators on Windows if PATH`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo\\:bar', 'PATH')).toBe('foo:bar')
})
test(`doesn't convert escaped separators on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('foo\\:bar', 'PATH')).toBe('foo:bar')
})
test(`converts a separator even if preceded by an escaped backslash`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo\\\\:bar', 'PATH')).toBe('foo\\\\;bar')
})
test(`converts multiple separators if PATH`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo:bar:baz', 'PATH')).toBe('foo;bar;baz')
})
test(`resolves an env variable value`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo-$VAR1')).toBe('foo-value1')
})
test(`resolves an env variable value with curly syntax`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
// eslint-disable-next-line no-template-curly-in-string
expect(varValueConvert('foo-${VAR1}')).toBe('foo-value1')
})
test(`resolves multiple env variable values`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo-$VAR1-$VAR2')).toBe('foo-value1-value2')
})
test(`resolves an env variable value for non-existant variable`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('foo-$VAR_POTATO')).toBe('foo-')
})
test(`resolves an env variable with a JSON string value on Windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('$JSON_VAR')).toBe(JSON_VALUE)
})
test(`resolves an env variable with a JSON string value on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('$JSON_VAR')).toBe(JSON_VALUE)
})
test(`does not resolve an env variable prefixed with \\ on Windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
})
test(`does not resolve an env variable prefixed with \\ on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
})
test(`resolves an env variable prefixed with \\\\ on Windows`, () => {
isWindowsMock.__mock.returnValue = true
isWindowsMock.mockReturnValue(true)
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
})
test(`resolves an env variable prefixed with \\\\ on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
isWindowsMock.mockReturnValue(false)
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
})
+1 -1
View File
@@ -84,7 +84,7 @@ function parseCommand(args) {
}
function getEnvVars(envSetters) {
const envVars = Object.assign({}, process.env)
const envVars = {...process.env}
if (process.env.APPDATA) {
envVars.APPDATA = process.env.APPDATA
}
+2 -1
View File
@@ -1 +1,2 @@
export default () => process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)
export default () =>
process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)