A private collection of utilities for developing tools to help maintain AngularJS-related GitHub repositories.
UNLICENSE License
A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub repositories.
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
run(rawArgs: string[], doWork?: ({[key: string]: string}) => any): Promise
: Parse the argumentsIt 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
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:
number
(ArgSpec.Unnamed
only)string
(value: any) => boolean
string
string|boolean
CleanUper
: A utility to help coordinate arbitrary tasks with their associated clean-up
process.
The general idea is this:
something
.something
.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).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 theCleanUper
. 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 alsotaskId
. If an error occurs, leave taskId
Requires:
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-lineargSpecs
.)
messages
: A (possibly nested) {[messageKey: string]: string}
map with at least the followingusage
instructionsHeaderTmpl
headerTmpl
errors
:
ERROR_unexpected
warnings
:
WARN_experimentalTool
versionInfo
: A {name: string, version: string}
map with values retrieved from the mainpackage.json
(i.e. the first package.json
to be found starting from the main file'sRequires:
{[messageKey: string]: string}
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
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 Git
s --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:
string
string
string[]
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) andofferToCleanUp()
: Requests confirmation to perform the scheduled clean-up tasks. If the userphase()
: It will report the beginning and end of a "phase" (see Phase
), do some work andreportAndRejectFnGen()
).reportAndRejectFnGen()
: Generates a callback that will report the specified error (plus anyRequires:
Logger
CleanUper
{[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.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.