0

I have an npm package that manages my github repository and has scripts that build my publishable npm package. Due to the nature of the package, the published npm package (the distribution) cannot match my repository's package (the source). I am moving closer to test-driven development and continuous integration, but am learning it step-by-step. Here is the current flow and it works flawlessly, so far:

From the command line:

> npm run patch
  1. runs npm version patch
    1. This invokes source's preversion,
      1. cleans the distro: npm run clean
      2. runs the tests: npm test
        1. This invokes pretest,
          • npm run build
        2. Runs distro's tests
          • Failure: Errors and process ends
          • Success: Branch complete,
    2. invokes the source's postversion:
      • git push all commits and tags
  2. runs distro's npm version patch
    1. invokes distro's postversion
      • npm publish

(Source) package.json

{
    ...,
    "scripts": {
        "patch": "npm version patch && cd dist && npm version patch",
        "minor": "npm version minor && cd dist && npm version minor",
        "major": "npm version major && cd dist && npm version major",
        "preversion": "npm run clean && npm test",
        "clean": /* clean commands */,
        "pretest": "npm run build",
        "test": "cd dist && npm test",
        "postversion": "git push origin --all && git push origin --tags"
    },
    ...
}

(Distro) package.json

{
    ...,
    "scripts": {
        "test": /* test commands */,
        "postversion": "npm publish"
    },
    ...
}

I would like to have a simpler interface. As you can see, I have to npm run <major|minor|patch>. I would instead like to npm run dist with a commandline arg passed to both npm versions.

Example:

> npm run dist patch
--------------------
<<< npm version patch
<<< cd dist && npm version patch

> npm run dist major
--------------------
<<< npm version major
<<< cd dist && npm version major

Is it possible to pass commandline args down the tree? Or, better yet, can I distribute a commandline arg across commands in a single scripts entry? I can easily add an entry to scripts that accepts a commandline argument, but cannot seem to figure out how to share that argument more than once with writing a separate .js script.

Fuzzical Logic
  • 12,947
  • 2
  • 30
  • 58
  • Running on *nix platforms only, your npm scripts; `patch`, `minor`, and `major`, can be replaced with one that utilizes a bash function, e.g. `"dist": "func () { arg=${1:-patch}; npm version \"$arg\" && cd dist && npm version \"$arg\"; }; func"`. Via your CLI run either: **1)** `$ npm run dist` (note: when no arg is passed, the `arg=${1:-patch};` part in `func`'s body, defaults the arg to `patch`). **2)** Or run: `$ npm run dist `, whereby `` should be substituted with either; `patch`, `minor`, or `major`. Windows `cmd.exe` will obviously choke at a bash function. My answers... – RobC Feb 04 '19 at 11:57
  • [here](https://stackoverflow.com/questions/51388921/pass-command-line-args-to-npm-scripts-in-package-json/51401577#answer-51401577) and [here](https://stackoverflow.com/questions/52656882/cross-platform-way-to-pass-environment-variables-as-arguments-to-npm-scripts/52672999#52672999) explain why args can't be passed via the CLI to the middle of a script (they can only be passed to the end) and offer solutions to overcome npm's limitation. For x-platform consider shelling out the `npm run` cmds via a _node.js_ script. However, in your scenario you're utilizing `pre` and `post` hooks too… – RobC Feb 04 '19 at 11:57
  • Unfortunately, when shelling out the `npm run` cmd via _node.js_'s `child_process.exec()` they are running in a child process, so your `pre` and `post` hooks will be ignored. Essentially for x-platform you'll need to shell out the cmds to allow args to the middle of a npm-script and also invoke the `pre` and `post` hooks from within the _node.js_ script too. Whilst, yes you can pass args down the tree as per this [answer](https://stackoverflow.com/questions/40495116/how-to-pass-a-command-line-argument-to-a-nested-script#answer-40508801), your primary issue is passing args to middle of script. – RobC Feb 04 '19 at 11:58
  • @RobC: I'll look at the resources. Thank you! Unfortunately, I'm on Win, but I can might make a .bat or .cmd work. So, if I'm understanding correctly, the hooks will stop working when if I utilize a `child_process`? Sounds like if I ***do*** find a pure-npm solution (which sounds unlikely), I might have to answer my own question... – Fuzzical Logic Feb 04 '19 at 13:41
  • Yes, the hooks get ignored. For instance, in a nodejs script obtaining the arg with `const arg = process.argv[2]';` then shelling out your cmd with `require('child_process').execSync(\`npm version ${arg} && cd dist && npm version ${arg}\`, { stdio:[0, 1, 2] });` both your `preversion` and `postversion` scripts didn't run (however they did using the bash function - i.e. when its the same process, not a child). Think you'll need to also invoke the hooks, e.g. `execSync(\`npm run preversion && npm version ${arg} && npm run postversion && cd dist && npm version ${arg}\`)`. May be worth exploring. – RobC Feb 04 '19 at 14:01
  • [npm-run-all](https://www.npmjs.com/package/npm-run-all) - "maybe" you could do something with its [argument placeholders](https://github.com/mysticatea/npm-run-all/blob/HEAD/docs/npm-run-all.md#argument-placeholders) feature. – RobC Feb 04 '19 at 14:01
  • @RobC : I wouldn't mind one or two npm-based dependencies. The idea is that I have a lot of webcomponents that I'd like to package, so I need a standard structure. Convention for webcomponents is to package the distro separately from the source, which is what has caused this exploration. If you can find a solution, please feel free to answer. I'd be glad to help to tailor an answer for others in my position in the future. Your comments have been invaluable so far. – Fuzzical Logic Feb 05 '19 at 01:52

0 Answers0