arquillian / arquillian-spacelift

Arquillian process and package manager. Makes executing an external process or fetching platform depends dependencies an easier job
4 stars 7 forks source link

= Arquillian Spacelift image:https://travis-ci.org/arquillian/arquillian-spacelift.svg?branch=master["Build Status", link="https://travis-ci.org/arquillian/arquillian-spacelift"]

Arquillian process and package manager. Makes executing an external process or fetching platform depends dependencies an easier job.

== Making it part of your extension

In your project, import following artifact:

[source,xml]

org.arquillian.spacelift arquillian-spacelift ${version.arquillian.spacelift}

You can use Spacelift both with and without Arquillian.

== How to use the extension

Arquillian Spacelift provides a set of tools (and tasks) that can be used to encapsulate execution of any command into block that can be executed asynchronously and repeated if needed. You reuse a set of existing tasks and implement your own tasks.

=== Task

Arquillian Spacelift provides you a concept of a task. Task is isolated amount of work, defined by its input, output and transition function that transforms input into output. Task is always executed asynchronously.

How do I create new tasks?:: Task is defined by class that represents its payload. You prepare tasks by calling +Spacelift+ utility + [source,java]

Spacelift.task(DownloadTool.class)

+ Once task is created, you get access to API defined by task class itself. I have task created. How do I execute it?:: Just call +execute()+. This will asynchronously send task to execution service that will be responsible for its execution. How do I run more tasks together?:: Task can be chained together by using +then(NextTaskName.class)+ call. There is following rules for chaining tasks: Input of next task must much output of current task. If next task input is type of +Object+, it can be chained to any task. +Object+ usually means that you don't care about input of next task at all. I already have input for a task. How do I pass it to the task?:: Just call +Spacelift.task(input, NextTaskName.class)+ How do I create my own tasks?:: Extend abstract class +Task+ and implement +process(INPUT)+ method.

==== Execution

Calling +execute()+ on a task will create an execution. You can use this object to reference execution in future.

Blocking execution:: You can run +await()+ or +awaitAtMost(long,TimeUnit)+ to block current thread and get the result. For latter call, if result in not computed within time limit, +TimeoutExecutionException+ is thrown. Scheduled execution:: You can force Spacelift to re-execute a chain of task periodically until results satisfies a condition or timeout is met by calling +until(long,TimeUnit,ExecutionCondition)+ call. By default, this will be schedule to re-execute every 500 ms. You can change this behavior by +reexecuteEvery(long,TimeUnit)+ call. Terminating execution:: You can kill the execution by calling +terminate()+ method. After terminating, you might be able to retrieve partial execution value by calling +await()+ but this behavior cannot be guaranteed for all types of tasks, as execution might be atomic. In such circumstances, task should return +null+ if it figures out if was forcefully terminated before it finished the work.

Current tasks are:

Command tool provides following API:

Program name:: Program name is defined by +processName(String)+. It must be on system path or it must be a full path. Spacelift does not check for its validity. Program parameters:: Program parameters are defined by +parameter(String)+, +parameters(String...)+, +parameters(List)+ and +splitToParameters(String)+. The last method splits a string into sequence of parameters according to non-escaped spaces. Program command:: Instead of setting program name and program parameters, you can use +command(Command)+ and +command(CommandBuilder)+ methods to define what will be executed. These methods will override any values set by prior program name and parameters calls. Process exit value:: Process is expected to exit with value +0+. It it exits with different value, +ExecutionException+ is thrown. However, you can override this behavior via +shouldExitWith(int...)+ call. Process interaction:: You can consume process output and provide an input to the process execution. Use +interaction(ProcessInteraction)+ or +interaction(ProcessInteractionBuilder)+ call. Working environment:: By default, process inherits working directory and environment of currently running JVM process. If you are not happy with such behavior, you can use +workingDir(String)+ and +addEnvironment(Map)+ or +addEnvironment(String...)+ methods to modify it. Cleanup:: By default, process is terminated with JVM shutdown. If you want to change that behavior, you can invoke +runAsDaemon(true)+ method.

Command tool returns +ProcessResult+. You can use this object for instance to check output returned by the command.

CommandTool is nice but I want to have something platform independent. How do I achieve that?:: Create your own tool or command and reuse existing +CommandTool+ there.

=== ProcessInteraction

ProcessInteraction defines a way how to interact with and handle output of process executed by +CommandTool+. You have +ProcessInteractionBuilder+ convenience builder available:

Input handling:: Use +when(String)+ and +replyWith(String)+ or +terminate()+ to define non-interactive handling of process input. Process output, split into separate lines is matched against pattern provided by +when(String)+. Answer can either be a string to be typed or you can force process termination by using +terminate()+ Output/error printing:: Use +when(String)+ and +printToOut()+ or +printToErr(String)+ to define patterns that if matched against output line, are printed either to standard output or standard error output Process name:: By default, a process output is prefixed by process name, defined by first parameter of +Command+. Use +outputPrefix(String)+ call to override this prefix. You can also set it to +null+ or empty string if you want process output to be indistinguishable from other output Initial input:: Some commands might require you to provide input before the very first output is available. In such cases, you can use +whenStarts()+ and +typeIn(String)+ combination to provide text that will be written to process input right after process is started

== TODO

Currently missing features:

== Releasing new version

In order to release new version, execute following Maven command:

[source,bash]

mvn clean release:prepare release:perform

Then:

  1. Verify the build from staging repository
  2. Make sure all JIRAs are closed
  3. Release version in JIRA and create next version if not available
  4. Promote the build to the stable Maven repository
  5. Push commits and tag created by +maven-release-plugin+ to the repository.