Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Merge branch 'master' into JENKINS-29875
Browse files Browse the repository at this point in the history
  • Loading branch information
amuniz committed Aug 14, 2015
2 parents ad5a5d1 + 5c3cbc2 commit b9c368b
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Expand Up @@ -2,6 +2,10 @@

Only noting significant user changes, not internal code cleanups and minor bug fixes.

## 1.10 (upcoming)

* [JENKINS-29890](https://issues.jenkins-ci.org/browse/JENKINS-29890): `input` step submitter was not being consistently logged.

## 1.9 (Aug 06 2015)

* _Running Steps_ link is now called _Workflow Steps_ as it will show steps for workflows that have long since completed.
Expand Down
4 changes: 2 additions & 2 deletions COMPATIBILITY.md
Expand Up @@ -221,8 +221,8 @@ Do not necessarily need any special integration, but are encouraged to use `Once

## Custom steps

Plugins can also implement custom Workflow steps with specialized behavior by adding a dependency on `workflow-step-api`.
Generally you will extend `AbstractStepImpl`, `AbstractStepDescriptorImpl`, and `AbstractStepExecutionImpl` (or `AbstractSynchronousStepExecution`).
Plugins can also implement custom Workflow steps with specialized behavior.
See [here](step-api/README.md) for more.

## Historical background

Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -64,6 +64,8 @@ and browse [localhost:8080](http://localhost:8080/).

# Presentations

Jenkins Office Hour on Workflow for plugin developers: [video](https://www.youtube.com/watch?v=4zdy7XGx3PA)

Jenkins Workflow: What’s Up? (JUC DC) (Jun 2015): [slides](http://www.slideshare.net/jgcloudbees/juc-dc-2015-workflow-whats-up)

Workflow Meetup London (Mar 2015): [slides](http://www.slideshare.net/jgcloudbees/london-workflow-summit-kkjg)
Expand Down
83 changes: 83 additions & 0 deletions step-api/README.md
@@ -0,0 +1,83 @@
# Writing Workflow steps

Plugins can implement custom Workflow steps with specialized behavior by adding a dependency on `workflow-step-api`.

## Creating a basic synchronous step

When a Workflow step does something quick and nonblocking, you can make a “synchronous” step.
The Groovy execution waits for it to finish.

Extend `AbstractStepImpl`.
Define mandatory parameters in a `@DataBoundConstructor`.
Define optional parameters using `@DataBoundSetter`.
(Both need matching getters.)

Extend `AbstractSynchronousStepExecution` (conventionally a nested `public static class Execution`), parameterized with the desired return value of the step (or `Void` if it need not return a value).
The `run` method should do the work of the step.
You can `@Inject` the step object to access its configuration.
Use `@StepContextParameter` to inject contextual objects you require, as enumerated in `StepContext.get` Javadoc;
commonly required types include `Run`, `TaskListener`, `FilePath`, `EnvVars`, and `Launcher`.

Extend `AbstractStepDescriptorImpl`.
Pass the execution class to the super constructor.
Besides a display name, pick a function name which will be used from Groovy scripts.

Create a `config.jelly` form with databinding for all the parameters, for use from _Snippet Generator_.
You can use the `StepConfigTester` test utility in `workflow-step-api` (`tests` classifier) to verify that all fields are correctly bound.
The descriptor can also have the usual methods complementing `config.jelly` for field validation, etc.

## Creating an asynchronous step

For the more general case that a Workflow step might block in network or disk I/O, and might need to survive Jenkins restarts, you can use a more powerful API.
This relies on a callback system: the Workflow engine tells your step when to start, and your step tells Workflow when it is done.

Extend `AbstractStepExecutionImpl` rather than `AbstractSynchronousStepExecution`.
You will be implementing a `start` method.
Normally it should do any quick setup work and then return `false`, meaning the step is still running.
Later you can call `getContext().onSuccess(returnValue)` (once) to make the step complete normally.
Or, `getContext().onFailure(error)` to make the step throw an exception.

Make sure all your injected parameters are `transient`; in the case of the step object (if configuration is needed), use `@com.google.inject.Inject(optional=true)`.
You can keep other `transient` fields too; override `onResume` to recreate transient state after a Jenkins restart if you need to.
You can also keep non-`transient` fields, assuming they are `Serializable`.
Do not forget to declare

```java
private static final long serialVersionUID = 1L;
```

You should also implement `stop` to terminate the step.
It could simply

```java
getContext().onFailure(cause);
```

but generally it will need to interrupt whatever process you started.

## Creating a block-scoped step

Workflow steps can also take “closures”: a code block which they may run zero or more times, optionally with some added context.

Override `takesImplicitBlockArgument` in your descriptor.
In `start`, or thereafter, call

```java
getContext().newBodyInvoker().
withContext(…something…).
withCallback(BodyExecutionCallback.wrap(getContext())).
start();
```

The above returns the same value as the block.
The callback may also be a `TailCall` to do some cleanup,
or any other `BodyExecutionCallback` to customize handling of the end of the block.

You can pass various contextual objects, as per `@StepContextParameter` above.

`stop` is optional.

## Using more APIs

You can also add a dependency on `workflow-api` which brings in more Workflow-specific features.
For example you can then receive a `FlowNode` as a `@StepContextParameter` and call `addAction` to customize the _Workflow Steps_ view.
Expand Up @@ -141,16 +141,25 @@ public HttpResponse doSubmit(StaplerRequest request) throws IOException, Servlet
@RequirePOST
public HttpResponse doProceed(StaplerRequest request) throws IOException, ServletException, InterruptedException {
preSubmissionCheck();
User user = User.current();
if (user!=null){
run.addAction(new ApproverAction(user.getId()));
listener.getLogger().println("Approved by " + hudson.console.ModelHyperlinkNote.encodeTo(user));
}
Object v = parseValue(request);
return proceed(v);
}

/**
* Processes the acceptance (approval) request.
* This method is used by both {@link #doProceedEmpty()} and {@link #doProceed(StaplerRequest)}
*
* @param v An object that represents the parameters sent in the request
* @return A HttpResponse object that represents Status code (200) indicating the request succeeded normally.
* @throws IOException
*/
public HttpResponse proceed(Object v) throws IOException {
User user = User.current();
if (user != null){
run.addAction(new ApproverAction(user.getId()));
listener.getLogger().println("Approved by " + hudson.console.ModelHyperlinkNote.encodeTo(user));
}

outcome = new Outcome(v, null);
getContext().onSuccess(v);

Expand All @@ -161,7 +170,9 @@ public HttpResponse proceed(Object v) throws IOException {
return HttpResponses.ok();
}

/** Used from the Proceed hyperlink when no parameters are defined. */
/**
* Used from the Proceed hyperlink when no parameters are defined.
*/
@RequirePOST
public HttpResponse doProceedEmpty() throws IOException {
preSubmissionCheck();
Expand Down
Expand Up @@ -57,6 +57,7 @@ public POSTHyperlinkNote(String url, int length) {
super("#", length);
if (url.startsWith("/")) {
StaplerRequest req = Stapler.getCurrentRequest();
// When req is not null?
if (req != null) {
url = req.getContextPath() + url;
} else {
Expand All @@ -66,8 +67,10 @@ public POSTHyperlinkNote(String url, int length) {
if (rootUrl != null) {
url = rootUrl + url.substring(1);
} else {
LOGGER.warning("You need to define the root URL of Jenkins");
// hope that / works, i.e., that there is no context path
// TODO: Does not works when there is a content path, p.e. http://localhost:8080/jenkins
// This message log should be an error.
LOGGER.warning("You need to define the root URL of Jenkins");
}
}
}
Expand Down

0 comments on commit b9c368b

Please sign in to comment.