A private collection of utilities for developing tools to help maintain (AngularJS-related) GitHub
repositories.
-
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:
-
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:
- Schedule a task to clean up after
something
. - Do
something
. - ...possibly do other things here...
- If anything goes wrong, the app will be able to clean up (or show instructions to the user).
- 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.
-
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
:
warnings
:
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 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
}
-
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:
- 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.