@plurid/joiner
TypeScript icon, indicating that this package has built-in type declarations

0.0.0-6 • Public • Published



License: DEL

joiner

Multi/Mono-Repository Task Runner


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, from the dashboard, or from the 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

It is recommended that joiner is installed globally. To install, NodeJS is presumed to be already on the system, run the command

npm install --global @plurid/joiner

or

yarn global add @plurid/joiner

If global installation is not an option or not preferred, run the command using npx

npx @plurid/joiner <joiner commands and options>

Usage

Setup

Initialize by running, in the root folder of the project(s), the command

joiner initialize

joiner requires† a joiner‡ configuration file where the packages paths must be registered, using deon or yaml, such as:

{
    packages [
        /path/to/package-1
        /path/to/package-2
    ]
}

Catch-all paths can be used with /* such as

{
    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.

The packages paths are resolved relative to the folder from where the command is called. See 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 or yaml.

The joiner.deon fields with example and default values:

{
    // 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

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).

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

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.

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

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.

{
    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

    | .
    | - packages
        | - package-a
        | - package-b
            | - package-b1
            | - package-b2
    | - scripts
        | - joiners

The folder ./scripts/joiners contains multiple joiner.deon (or .yaml) files. For example

// joiner-b2-a.deon
{
    packages [
        ./packages/package-b/package-b2
        ./packages/package-a
    ]
}
# joiner-all.yaml
---
packages:
  - ../../packages/package-b/*
  - ../../packages/package-a

Running the command

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

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

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

Version

@plurid/joiner • the CLI application

Codeophon

Readme

Keywords

Package Sidebar

Install

npm i @plurid/joiner

Weekly Downloads

0

Version

0.0.0-6

License

SEE LICENSE IN LICENSE

Unpacked Size

2.56 MB

Total Files

417

Last publish

Collaborators

  • ly3xqhl8g9