@gkalpak/ng-maintain-utils

A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.

Stats

StarsIssuesVersionUpdatedCreatedSize
@gkalpak/ng-maintain-utils
110.1.32 months ago5 years agoMinified + gzip package size for @gkalpak/ng-maintain-utils in KB

Readme

ng-maintain-utils Build Status

Description

A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.

Usage

You should generally not use it. You would use tools built on top of it, for example:

I may use it for building other tools (see above). Here is a brief overview of what's in the box:

  • AbstractCli: Can serve as a base-class for creating a Cli object that can orchestrate the execution of some type of work, based on a list of "raw" command-line arguments. It can display version info (with --version), show usage instructions (with --usage), outline the commands that need to be executed to complete the task at hand (with --instructions) - a sort of "dry-run", report the beginning/end of execution, etc.

    It exposes the following (public) methods:

    • getPhases(): Phase[] (abstract): This method must be overwritten and return an array of Phase objects (to be used for displaying instructions in the "dry-run" mode).
    • run(rawArgs: string[], doWork?: ({[key: string]: string}) => any): Promise: Parse the arguments and take appropriate action (see above).

    It also provides a number of "protected" methods, that can be overwritten by sub-classes:

    • _displayExperimentalTool(): void
    • _displayHeader(headerTmpl: string, input: {[key: string]: string}): void
    • _displayInstructions(phases: Phase[], input: {[key: string]: string}): void
    • _displayUsage(usageMessage: string): void
    • _displayVersionInfo(): void
    • _getAndValidateInput(rawArgs: string[], argSpecs: ArgSpec[]): Promise<{[key: string]: string}>
    • _insertEmptyLine<T>(value: T, isRejection?: boolean): T|Promise<T>
    • _theHappyEnd<T>(value: T): T
    • _theUnhappyEnd(err: any): Promise<any>

    Requires:

    • config: Config
  • ArgSpec/ArgSpec.Unnamed: Represents the specification for a command-line argument. When applied on a parsed arguments object (such as the ones returned by Utils#parseArgs()) it will extract the corresponding argument's value (either by name (ArgSpec) or by position (ArgSpec.Unnamed)), fall back to a default value if necessary, vaidate the value and assign it to the specified input object under the appropriate key.

    Requires:

    • index: number (ArgSpec.Unnamed only)
    • key: string
    • validator: (value: any) => boolean
    • errorCode: string
    • defaultValue?: string|boolean
  • CleanUper: A utility to help coordinate arbitrary tasks with their associated clean-up process.

    The general idea is this:

    1. Schedule a task to clean up after something.
    2. Do something.
    3. ...possibly do other things here...
    4. If anything goes wrong, the app will be able to clean up (or show instructions to the user).
    5. When cleaning up after something is no longer necessary, unschedule the clean-up task.

    Provides the following methods:

    • cleanUp(listOnly: boolean): Promise: Perform all clean-up tasks (or just list them). (Either way, the clean-up task queue is emptied.)
    • getCleanUpPhase(): Phase: Returns a clean-up Phase object (suitable for UiUtils#phase()).
    • hasTasks(): boolean: Returns whether or not there are any clean-up tasks scheduled.
    • registerTask(description: string, cb: () => Promise): TaskId: Register a task with the CleanUper. You can use the returned, unique TaskId for scheduling/unscheduling the task.
    • schedule(taskId: TaskId): void: Schedule a clean-up task.
    • unschedule(taskId: TaskId): void: Schedule (the last instance of) a clean-up task.
    • withTask(taskId: TaskId, fn: () => any): Promise: Schedule taskId and execute fn (can also return a promise). If all goes well, unschedule taskId. If an error occurs, leave taskId in the clean-up task queue.

    Requires:

    • logger: Logger
  • Config: Creates a Config object based on the specified messages and argSpecs (falling back to some default values if necessary). It exposes the following properties:

    • argSpecs: A (possibly empty) array of ArgSpec objects.
    • defaults: A {[argument: string]: string|number} map of default values per command-line argument keys. (Automatically extracted for argSpecs.)
    • messages: A (possibly nested) {[messageKey: string]: string} map with at least the following messages:
      • usage
      • instructionsHeaderTmpl
      • headerTmpl
      • errors:
        • ERROR_unexpected
      • warnings:
        • WARN_experimentalTool
    • versionInfo: A {name: string, version: string} map with values retrieved from the main module's package.json (i.e. the first package.json to be found starting from the main file's directory and moving upwards).

    Requires:

    • messages: {[messageKey: string]: string}
    • argSpecs: ArgSpec[]
  • GitUtils: A collection of Git-related command-wrappers and utilities. Mainly spawns Git commands in a separate process and (promises to) return the output. Support for commands is added in an "as-needed" basis. Currently, the available commands/utilities include:

    • abortAm(): Promise
    • abortRebase(): Promise
    • checkout(branch: string): Promise
    • clean(mode?: string = 'interactive'): Promise
    • countCommitsSince(commit: string): Promise<number>
    • createBranch(branch: string): Promise
    • deleteBranch(branch: string, force?: boolean): Promise
    • diff(commit: string, noColor?: boolean): Promise
    • diffWithHighlight(commit: string): Promise
    • diffWithHighlight2(commit: string): Promise
    • getCommitMessage(commit: string): Promise<string>
    • getLastCommitMessage(): Promise<string>
    • log(oneline?: boolean, count?: number, noDecorate?: boolean): Promise
    • mergePullRequest(prUrl: string): Promise
    • pull(branch: string, rebase?: boolean): Promise
    • push(branch: string): Promise
    • rebase(commit: string|number, interactive?: boolean): Promise
    • reset(commit: string, hard?: boolean): Promise
    • setLastCommitMessage(message: string): Promise
    • updateLastCommitMessage(getNewMessage: (oldMessage: string) => string): Promise

    Requires:

    • cleanUper: CleanUper
    • utils: Utils
  • GitUtils.DiffHighlighter: Can be used to enhance a diff by highlighting areas of interest. The general implementation is loosely based on the idea of diff-highlight, although the matching heuristics and coloring (among other things) are different.

    It exposes the underlying streams via:

    • getInputStream(): stream.PassThrough
    • getOutputStream(): stream.PassThrough

    Requires:

    • styles?:

      {
        lineRemoved?: (text: string) => string,
        lineAdded?: (text: string) => string,
        areaRemoved?: (text: string) => string,
        areaAdded?: (text: string) => string
      }
      
  • GitUtils.DiffHighlighter2: An alternative, API-compatible implementation of GitUtils.DiffHighlighter. The highlighting is more accurate, as it is able to only highlight the regions that have changed. The main drawback is that it fails to show removed/added empty lines, because of its dependency on Gits --word-diff=plain option.

    Similar to GitUtils.DiffHighlighter, it exposes the underlying streams via:

    • getInputStream(): stream.PassThrough
    • getOutputStream(): stream.PassThrough

    Requires:

    • styles?:

      {
        lineRemoved?: (text: string) => string,
        lineAdded?: (text: string) => string,
        areaRemoved?: (text: string) => string,
        areaAdded?: (text: string) => string
      }
      
  • Logger: A simple helper providing minimal logging utilities. This is mostly used in order to make it easier to test logging behavior without affecting console methods. Provides the following methods:

    • debug(): Delegate to console.debug().
    • error(): Delegate to console.error().
    • info(): Delegate to console.info().
    • log(): Delegate to console.log().
    • warn(): Delegate to console.warn().
  • Phase: A simple wrapper for "phase" entities (with validation). A "phase" is a description of a unit of work, including an ID, a short description, a list of the tasks involved and an error message (or code) specific to this "phase".

    Requires:

    • id: string
    • description: string
    • instructions?: string[]
    • error?: string (Can be either an error message or an error code.)
  • UiUtils: A collection of utilities useful for interacting with the user, including:

    • askQuestion(): Prompt the user with a question and (promise to) return the answer.
    • askYesOrNoQuestion(): Prompt the user with a yes-or-no question (e.g. a confirmation) and (promise to) resolve (for "yes") or reject (for "no").
    • offerToCleanUp(): Requests confirmation to perform the scheduled clean-up tasks. If the user turns the offer down, it will just list the pending tasks instead.
    • phase(): It will report the beginning and end of a "phase" (see Phase), do some work and properly handle possible errors (by means of reportAndRejectFnGen()).
    • reportAndRejectFnGen(): Generates a callback that will report the specified error (plus any extra error provided during invokation), will offer to clean up (if there are pending tasks and not configured otherwise) and return a rejection.

    Requires:

    • logger: Logger
    • cleanUper: CleanUper
    • errorMessages: {[errorCode: string]: string}
  • Utils: A collection of low-level, specific-purpose utilities, including:

    • asPromised(): Convert callback-based functions to promise-based.
    • interpolate(): Replace {{...}} placeholders in a string with values.
    • parseArgs(): Parse command-line arguments (and remove surrounding quotes).
    • resetOutputStyleOnExit(): Ensure the output style is reset when a process exists.
    • spawnAsPromised(): Spawn a sub-shell to run a (series of) command(s) with support for piping.
    • waitAsPromised(): setTimeout() wrapped in a promise.

Testing

The following test-types/modes are available:

  • Code-linting: npm run lint Lint JavaScript files using ESLint.

  • Unit tests: npm run test-unit Run all the unit tests once. These tests are quick and suitable to be run on every change.

  • E2E tests: npm run test-e2e Run all the end-to-end tests once. These test may hit actual API endpoints or perform expensive I/O operations and are considerably slower than unit tests.

  • All tests: npm test / npm run test Run all of the above tests (code-linting, unit tests, e2e tests). This command is automatically run before npm version and npm publish.

  • "Watch" mode: npm run test-watch Watch all files and rerun the unit tests whenever something changes. For performance reasons, code-linting and e2e tests are omitted.

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.