3.23.0 • Published 5 years ago

@oscars/ftool v3.23.0

Weekly downloads
-
License
UNLICENSED
Repository
-
Last release
5 years ago

FTool

What is it?

FTool is our new global JS tooling package for the Focus repositories. It contains the tooling for our code, from testing and building to releasing, and everything else we require done in terms of frontend tooling. It is essentially the focus-tooling Node tooling rewritten as a much more easy-to-use global package, with extra features, and the latest updates.

No more tooling.js, just FTool. The same commands that existed in the Node/Make tooling are in FTool, as well as some new ones!

Installation

FTool is currently just a git repo, not it's own defined NPM package on a registry, hence installing it is a bit roundabout:

git clone https://git.nflex.io/Focus/ftool
cd ftool/
npm install
./build/ftool.js setup

To update the version of FTool you're using, simply pull the repo and rerun npm install. FTool is built in the postinstall script, so it gets rebuilt every time you npm install.

You need to refer to FTool via it's built JS file in the 1st instance to set it up. It will add an alias to your profile, then ask you to either reload your shell or execute your updated profile. Once you have done this you will have access to FTool via an alias, so you can use it anywhere on your system.

Usage

Using FTool is simple, all the commands that previously existed are the same, and there are some new ones. Simply call FTool with the name of the command you want. Use the -v flag for extra debugging info. use -h for help. As an example, say you wanted to build a release tarball, in the old tooling this would be:

make build-release

But in FTool, it would be done like this:

ftool build-release

See how these are similar? This was intentional, to enable smooth crossover. All the commands are the same, just called in this new way.

Here is a help output for a focus app; this shows the available commands, and provides some context as to what they do. Please note that this is just the tooling that a focus application has access to, and the toolchain changes depending on what type of repository you are working with.

Usage: ftool <command1> <command2> [-h] [-v] [-f ["flag1" "flag2"]]

Commands:
    build-assets                              Copies over fonts and images to the build dir
    build-latest                              Builds a .tgz of the latest dirty tag in git
    build-release                             Builds a .tgz of the latest clean tag in git
    bump-major                                Bumps to a new major version
    bump-minor                                Bumps to a new minor version
    bump-patch                                Bumps to a new patch version
    test-coverage-statements                  Gets the coverage of statements
    test-coverage-branches                    Gets the coverage of branches
    test-coverage-lines                       Gets the coverage of lines
    test-coverage-functions                   Gets the coverage of functions
    test-coverage-ignored                     Gets the coverage of ignored
    git-check-clean                           Check you have no uncommited changes
    git-check-on-develop                      Check you are on branch develop
    git-check-on-master                       Check you are on branch master
    git-check-on-release                      Check you are on a valid release branch
    git-check-develop-up-to-date-with-remote  Check you are up to date
    check-git                                 Check you have no changes, are on develop, and up to date
    do-release                                Create and push a new minor release
    do-release-major                          Create and push a new major release
    do-release-patch                          Create and push a new patch release
    sec-audit                                 Run the security audit
    sec-audit-publish                         Publish the security audit
    notify-slack                              Send details of the latest clean release to Slack
    test-jshint                               Run the linter
    test-karma                                Run the karma tests directly
    test-complete                             Run the complete karma suite
    utl-api                                   Updates your package.json to the latest version of api
    utl-common                                Updates your package.json to the latest version of common
    utl-core                                  Updates your package.json to the latest version of core
    utl-tooling                               Updates your package.json to the latest version of tooling
    utl-utils                                 Updates your package.json to the latest version of utils
    get-latest-tag                            Get the latest dirty tag
    name                                      Get the name of the repo

Flags:
  --version      Show version number               [boolean]
  -f, --flag     A flag to alter an ftool process    [array]
  Options:
        clean-tag-build  Prevents building the repo, unless the tag is clean
        skip-pypi-check  Disables checking the PyPI server for the package before build
        skip-publish     Disables publishing to PyPI
        skip-build-test  Skip testing repo when building [NOTE: WILL PUBLISH UNTESTED BUILD]
  -v, --verbose  Print out extra info              [boolean]
  -h, --help     Show help                         [boolean]

Tooling Design

Node API & Lodash FP

Node APIs are used in FTool, mainly fs and child_process. fs allows FTool to read and write files, as well as read directories. It uses child_process to execute shell commands in a synchronous and asynchronous way.

For the design and structure of FTool, there is a flavour of the Lodash we all know and tolerate. It's called lodash FP. Take a look at the docs!

It's a more functional programming oriented type of lodash, which makes heavy use of functions like flow, map, filter, and reduce. It looks rather daunting at first, but it is imperative to understand how these functions work, in order to have a full understanding of how FTool works.

Structure & Build Process

FTool is structured in an basic way, that hopefully makes sense. This is what it looks like:

ftool/
    package.json
    webpack.config.js
    src/
        ftool.js
        shell-plugin.js
        tools/
            git.js
            build.js
            test.js
            etc...

There are a couple files in there worth note, other than ftool.js and it's tools.

webpack.config.babel.js

The way FTool is built is somewhat different to how you would structure a normal Focus application or library. Firstly, it is a UMD module, which means it can be loaded via multiple module loader methods. In this case, it's mainly so that Node can run it directly. This is also why the target is set to Node.

In the externals, it transforms the node_modules list into an object with the key and value matching (and removing binary files), which allows it to resolve the externals while also allowing for the way tools are loaded in, via a require context. This allows for bringing in all of the tools in the tools directory.

The config uses 2 plugins; the BannerPlugin is used to add a shebang to the top of the built file, which indicates to the shell you are using to use Node to execute this code. This assumes your system has the env utility in the /usr/bin/ directory. If this is wrong, edit it to point to your env executable.

The config uses a module rule to load both itself (the config), and the actual ftool code via the JS compiler Babel. This is primarily to utilise new, cleaner features where possible, and make the code as readable as possible.

The Chain Operator (|>)

This code has been rewritten using the arrow (|>) chaining operator, instead of the usual flow function in lodash-fp. This is mainly for aesthetic reasons, it improves code cleanliness, and makes it much more easy to visualise the data going through this chain of functions.

The chain operator is loaded in via the babel plugin @babel/plugin-proposal-pipeline-operator tc39 propoal babel docs. This is added to Babel to allow it to understand the new syntax.

The babel plugin for the chain operator is the only plugin used at the moment. It is using the default (minimal) proposal. This means that chaining cannot be done with asynchronous functions or async/await, so anything using it must be synchronous.

shell-plugin.js

The Shell Plugin is an implementation of shell command execution that is compatible with webpack 4. It uses the new Tapable API that Webpack 4 uses, so it does not throw a DeprecationWarning as the plugins currently available for this purpose do. It takes an array of commands to run, and executes them after Webpack is done building FTool.

The functionality here could be expanded if needed, to execute shell commands at any point in the build process. This can be done by tapping into Webpack via the hooks it provides hook docs.

Because the afterEmit hook used in the Shell Plugin has the Promise Tap, we can run these commands asynchronously, by wrapping the Node child_process exec function in a wrapper, called PromiseExecutorGenerator, which then gets mapped onto all the commands in a Promise.all, that then gets passed back to the Tap.

Not sure whether to spin this off into its own separate repo, not really needed unless this concept can be built upon for other purposes?

FTool.js

FTool is designed to firstly obtain variables about the current directory, things like; git details, name, type, dependencies, etc. This is the main set of information that FTool needs. This is compiled into an object called toolEnv. Obtuse name, i know.

Functions & Control Flow

A lot of the code in Ftool can be understood by logical reasoning, they are primarily composed functions, that pipe data through a series of relatively simple statements. A lot of these functions are defined at the top of the code, their names imply what they do. Some of them are more complex than others, but they are written to transform data structures in a readable way.

In these first few functions, probably the hardest to understand is getRepoType. It takes a list of repos organised by type, and a repo name, and returns what repo it is in, or undefined. Try to visualise the data going through each function, and grasp how these come together to do something useful.

Another important function to note, that you will find is used only in the toolEnv, which means it is used in the tools, is execPromise. It's a wrapper around Node's asynchronous exec function, that executes the command, pipes the stdout to the console, and returns a promise that will resolve when done, or reject if there was an error.

A word on reducers

There are some functions defined in their own little section, called reducers. They use the reduce function in lodash-fp, which takes 3 arguments in a curried fashion. These are the reducing function, the starting value, and the data, in that order. In this case, these reducing functions have their reducing functions and starting values defined already.

Since reduce is a curried function, that only executes when all of it's arguments have been supplied, the functionality is defined and the starting value given, the functions are unary - just expecting data. The functions are given a name that gives an idea about what the reducer does, but it can be implied via reasoning about the function.

Argument Parsing

Ftool uses a npm module called yargs-parser to parse the command line options. This returns an object (called argv in FTool) that contains the command line options in an easy to use form. Parsing the arguments into what's needed is not done though.

Firstly, the debugging is disabled if the -v flag is not set. Next the given flag(s) need to be checked for validity. This is what the arrow statement assigned to cmdOptsValid does. It makes sure that the flag(s) are defined as an option in the validOptions array at the top, except if you are in the focus main repo, in which case the flag is used to give a name to a new app or lib (the focus tooling ignores any flags set other than the first).

If the command options are valid, the options are transformed from an array of keys to an object with said keys set to true. This is done by chaining a map and on of the reducers mentioned earlier, called rArrayToObject.

Tools

The tools are designed to be self-contained functions, that can be executed with no arguments, to perform some specific task, given the toolEnv. They may import other pieces of code, including the Node API, or whatever else is needed.

In the tooling that has been created, each set of tools that can be thought of as performing closely related functions, such as releasing code, building code, or writing to Slack for example. This set of tools are created as a series of functions inside of one outer unary function that takes the toolEnv, making everything that the tooling needs available (in scope), hence why the actual tooling functions do not take arguments.

The tooling functions are not simply returned by the outer unary function. There is a specific structure that needs to be returned, to ensure the help and the functions are detected, transformed, and executed properly (see below).

In theory, the tooling file could contain any JS that returns the tool structure, and performs the desired function. There are some different approaches taken in the current toolset, as some tools are very similar, differing only in 1 specific variable, i.e the bump tooling, and the update to latest (utl) tooling.

This being said, the structure of the outer unary function is the standard design used in the current tooling set.

Tool Structure

{
        // Add all supported tooling sets separated by spaces
        'supportedType': 'app lib colo ftool repo-list',
        // Add your tooling functions here, with descriptive names
        'tool_func_1': func_1,
        'tool_func_2': func_2,
        'tool_func_3': func_3,
        ...,
        'helpMessages': {
            // You need a help message for each tooling function, the names must match.
            'tool_func_1': 'help_msg_1',
            'tool_func_2': 'help_msg_2',
            'tool_func_3': 'help_msg_3',
            ...
        }
}

Notes

Tools are not using the chain operator yet, needs to be done when more time is available.

If you need a tool, try to make it! Making good use of -v and dbgLog to debug is how this tooling was written, it should be usable for writing tools.

FTool exists to provide a stable way to get a lot of useful variables about the environment, most, if not all of what you would need to write frontend tooling. Even if you're missing something, it can be added.