UNPKG

@plurid/joiner

Version:
455 lines (313 loc) 14 kB
<p align="center"> <img src="https://raw.githubusercontent.com/plurid/joiner/master/about/identity/joiner-logo.png" height="250px"> <br /> <br /> <a target="_blank" href="https://github.com/plurid/joiner/blob/master/LICENSE"> <img src="https://img.shields.io/badge/license-DEL-blue.svg?colorB=1380C3&style=for-the-badge" alt="License: DEL"> </a> </p> <h1 align="center"> joiner </h1> <h3 align="center"> Multi/Mono-Repository Task Runner </h3> <br /> `joiner` is intended to sub-automate commands over a span of projects/packages/folders. `joiner` can run arbitrary commands in each target project, or specific commands (`update`, `commit`, etc.) based on supported workflows. `joiner` is a sub-automation tool in that the commands are manually called from the [`command-line`](#command-line-interface), from the [`dashboard`](#dashboard), or from the [`api`](#api), and it requires another publish/subscribe-like layer on top of it in order to reach full automation. Supported languages: + `JavaScript`/`TypeScript` For `JavaScript`/`TypeScript`, `joiner` can be used on its own or conjoined with `Yarn Workspaces`. ### Contents + [Install](#install) + [Usage](#usage) + [Setup](#setup) + [Command-Line Interface](#command-line-interface) + [Configuration File](#configuration-file) + [Dashboard](#dashboard) + [API](#api) + [Advanced Usage](#advanced-usage) + [Aliases](#aliases) + [Development](#development) + [High-Scale](#high-scale) + [Joiner Package](#joiner-package) + [Path Resolution](#path-resolution) + [Packages](#packages) + [Codeophon](#codeophon) ## Install It is recommended that `joiner` is installed globally. To install, [NodeJS](https://nodejs.org/en/) is presumed to be already on the system, run the command ``` bash npm install --global @plurid/joiner ``` or ``` bash yarn global add @plurid/joiner ``` If global installation is not an option or not preferred, run the command using `npx` ``` bash npx @plurid/joiner <joiner commands and options> ``` ## Usage ### Setup Initialize by running, in the root folder of the project(s), the command ``` bash joiner initialize ``` `joiner` requiresa `joiner`‡ configuration file where the packages paths must be registered, using [`deon`](https://github.com/plurid/deon) or `yaml`, such as: ``` deon { packages [ /path/to/package-1 /path/to/package-2 ] } ``` Catch-all paths can be used with `/*` such as ``` deon { packages [ /path/to/multi-package-folder/* /path/to/package-2 ] } ``` where the `multi-package-folder` is a directory containing multiple folders with their own `package.json`, or [`joiner.package`](#joiner-package). The packages paths are resolved relative to the folder from where the command is called. See [path resolution](#path-resolution). † when using `yarnWorkspace true` [`.deon`] the `packages` field can be removed/commented; `joiner` will look for the packages in the `workspaces` field of the root `package.json`. ‡ `joiner` will by default look for a `joiner.deon` file in the working directory, but the file can be arbitrarily named/placed, provided it is passed to the `-c, --configuration` option. ### Command-Line Interface ``` Usage: joiner <command> Options: -v, --version output the version number -c, --configuration <file> path to the ".deon" or ".yaml" configuration file (defaults: "joiner", "scripts/joiner", "scripts/joiner.packages") -h, --help display help for command Commands: manual the "joiner" manual dashboard configure a local web server with a global view over the "joiner" packages registered on the machine initialize [options] initialize the "joiner" configuration file list list joiner commandable packages run [options] <package> <command...> run an arbitrary command on package by name or on "all" packages command [options] <package> <command...> run the named commands specified in the "joiner" file on package by name or on "all" packages update [options] <package> update package by name or "all" packages patch [options] <package> patch package version by name or "all" packages commit [options] <package> commit package by name or "all" packages publish [options] <package> publish package by name or "all" packages ucom [options] <package> ucom - update, commit - package by name or "all" packages upcom [options] <package> upcom - update, patch, commit - package by name or "all" packages upcomlish [options] <package> upcomlish - update, patch, commit, publish - package by name or "all" packages develop start a server to listen for changes in the development watched packages and update the cross-dependencies ``` Instead of `package`, the signifier `all` can be used to run the command on all the registered packages. Instead of `package`, a zero-based index can be passed, `%<number>`, given the position of the package in the packages list (e.g., `joiner update %2` will update the third package as listed by `joiner list`). If `joiner` is configured with only one package, instead of `package` the signifier `self` can be used. To `run` a `command...` with flags, the divider `--` must be used, e.g. `joiner run all -- yarn add -D <some-development-dependency>`. ### Configuration File The `joiner` configuration file can be at the root of the packages/workspaces and the `CLI` will parse it by default, or it can be specified at runtime with the `-c, --configuration <file>` option. The `joiner` configuration file has as required fields only the `packages` field (or, if using Yarn Workspaces, the `yarnWorkspace` field set to `true`). The `joiner` configuration file can be formatted using [`deon`](https://github.com/plurid/deon) or `yaml`. The `joiner.deon` fields with example and default values: ``` deon { // required #packages // default false yarnWorkspace false // false | true // optional #package #commit #runFrom #development } packages [ /path/to/package /path/to/multi-package/* ] package { // default yarn manager yarn // yarn | npm // default npm publisher npm // yarn | npm // Names of the packages or paths of the folders to be ignored by the "all" signifier. // Helpful when the packages are registered in bulk with "/*" // and some of the folders are not actually packages (fixtures, specifications). // default [] ignore [] } commit { // At the moment, only git is supported. engine git // The commit message is formed from: // commitRoot + packageFolderName + commitDivider + commitMessage // default false combine false // false | true // The root of the packages/workspace. root '/path/to/root' // Use the full folder of the package in the commit message // or only the folder name of the package. fullFolder false // Separator between the packageFolderName and the commitMessage. // default ' > ' divider ' > ' // The actual commit messsage. // default 'setup: package' message 'setup: package' } // see Advanced Usage -> Path Resolution runFrom '' // see Advanced Usage -> Development development { // default all watchPackages 'all' // ['packageName'] | 'packageName' | 'all' serverPort 55000 watchDirectories [ build distribution dist ] externalPackages [] } ``` ### Dashboard In order to provide a global view of all the `joiner` configurations and packages from the machine, the dashboard server can be started by running: ``` joiner dashboard start ``` In order to populate the dashboard with configurations, the `joiner` configuration files must be registered ``` joiner dashboard register /path/to/joiner-configuration-file ``` <p align="center"> <img src="https://raw.githubusercontent.com/plurid/joiner/master/about/screenshots/ss-1.png" height="500px"> </p> ### API Once the dashboard server has been started, it can receive GraphQL-based API requests on `http://localhost:<port>/joiner` (the default port is `10100`: `http://localhost:10100/joiner`). ``` graphql input InputExecuteCommand { configurationID: String! command: String! package: String! } mutation ExecuteCommand($input: InputExecuteCommand!) { executeCommand(input: $input) { status error { type path message } } } ``` ## Advanced Usage ### Aliases Recommended `Joiner` Aliases for the terminal ``` bash alias j='joiner' alias jd='joiner dashboard' alias ju='joiner update' alias jua='joiner update all' alias jp='joiner patch' alias jpa='joiner patch all' alias jc='joiner commit' alias jca='joiner commit all' alias jpub='joiner publish' alias jpuba='joiner publish all' ``` ### Development Cross-linking packages depending on each other with symlinks becomes very fast a complete mess, especially when the dependency chain is beyond 2-3 links, and even more so when one of the packages does not play well with having a copy of itself in the dependency graph. `Joiner` goes the "dumb" way: instead of symlinking the complete folder into `node_modules`, giving rise to the mess in the first place, `joiner` merely watches and copies the build process output (`/build`, `/distribution`, or any other folder) of a package into the adequate dependency folder for each 'linked', that is referenced, package. To setup the packages linkage, the configuration file should have at least the `watchPackages` field, if not, all the registered packages will be watched. ``` deon development { // The packages which are targeted for development watch. // The server will listen for file changes in the `watch directory` of the `package` // and copy the files to the `node_modules` of all the packages which require them. // The catch-all 'all' can be used, or a single package can be passed. // default all watchPackages 'all' // ['packageName'] | 'packageName' | 'all' // Port for the server started with `joiner develop`. // default 55000 serverPort 55000 // default ['build', 'distribution', 'dist'] watchDirectories [ build distribution dist ] // Paths to other packages which need to be linked/watched/updated // but which do not belong to the same life-cycle management // as the top-defined `packages`. // default [] externalPackages [] } ``` To start the development server and the watchers, run the command ``` bash joiner develop ``` ### High-Scale For multi-/mono-repositories containing 100+ packages, it is generally useful to have a `/scripts/joiner` directory as close as possible to the root directory with multiple, segmented `joiner.yaml` files, appropriately named, e.g. `joiner.backends.yaml`, `joiner.frontends.yaml`. The `joiner` commands will then be run from the root directory, and all the `joiner.yaml` files will resolve the paths in a similar fashion. ### Joiner Package Instead of relying on the `package.json` file to specify the package-related data (name, dependencies), a `joiner.package.deon` (or `.yaml`) file can be created. ``` deon { name package-name } ``` This feature is recommended for using `joiner` with other languages besides `JavaScript`-based project, and/or for using `joiner` as a meta-controller of multiple separated projects. ### Path Resolution `Joiner` can be used to couple arbitrary packages, spread across the filesystem, and perform any kind of maintenance cycle (run commands, update, patch, commit, publish) on them specifically. The `joiner.deon` (or `.yaml`) files can be anywhere on the filesystem. Consider the following file structure ``` fs | . | - packages | - package-a | - package-b | - package-b1 | - package-b2 | - scripts | - joiners ``` The folder `./scripts/joiners` contains multiple `joiner.deon` (or `.yaml`) files. For example ``` deon // joiner-b2-a.deon { packages [ ./packages/package-b/package-b2 ./packages/package-a ] } ``` ``` yaml # joiner-all.yaml --- packages: - ../../packages/package-b/* - ../../packages/package-a ``` Running the command ``` bash joiner update all -c ./scripts/joiners/joiner-b2-a.deon ``` from the `root` directory will update all the packages mentioned in the `./scripts/joiners/joiner-b2-a.deon` file (`package-b/package-b2` first, and then `package-a`). While running the command ``` bash joiner update all -c ./joiner-all.yaml ``` from the `./scripts/joiners` directory will update all the packages in `./packages/package-b` and the `packages/package-a` package. In order to avoid running the command from a wrong directory, which will result in bad path resolution, the field `runFrom` can be specified ``` yaml runFrom: ../../ ``` which contains a path trunk, relative to the `joiner.deon` (or `.yaml`) file, from which the packages paths will be resolved, irrespective from where the `joiner` command is run. ## Packages <a target="_blank" href="https://www.npmjs.com/package/@plurid/joiner"> <img src="https://img.shields.io/npm/v/@plurid/joiner.svg?logo=npm&colorB=1380C3&style=for-the-badge" alt="Version"> </a> [@plurid/joiner][joiner-cli] • the CLI application [joiner-cli]: https://github.com/plurid/joiner/tree/master/packages/joiner-cli ## [Codeophon](https://github.com/ly3xqhl8g9/codeophon) + licensing: [delicense](https://github.com/ly3xqhl8g9/delicense) + versioning: [αver](https://github.com/ly3xqhl8g9/alpha-versioning)