Skip to content
This repository was archived by the owner on Feb 13, 2020. It is now read-only.

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
ikikko committed May 5, 2014
1 parent 3b43f40 commit 9fd1dc4
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 109 deletions.
62 changes: 15 additions & 47 deletions src/main/java/org/jenkinsci/plugins/typetalk/TypetalkNotifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ public TypetalkNotifier(String name, String topicNumber, boolean notifyWhenSucce
this.notifyWhenSuccess = notifyWhenSuccess;
}

// for test
TypetalkNotifier(boolean notifyWhenSuccess) {
this.name = null;
this.topicNumber = null;
this.notifyWhenSuccess = notifyWhenSuccess;
}

@Override
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
Expand All @@ -49,18 +42,16 @@ public BuildStepMonitor getRequiredMonitorService() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
String buildSummary = toBuildSummary(build);
if (buildSummary == null) {
return true;
}

final String rootUrl = Jenkins.getInstance().getRootUrl();
if (StringUtils.isEmpty(rootUrl)) {
throw new IllegalStateException("Root URL isn't configured yet. Cannot compute absolute URL.");
}

String message = makeMessage(build, buildSummary, rootUrl);
Long topicId = Long.valueOf(topicNumber);
// 前回からビルド成功で "ビルドが成功した場合も通知する" がオフの場合、通知しない
if (successFromPreviousBuild(build) && notifyWhenSuccess == false) {
return true;
}

// Typetalkに通知中...
listener.getLogger().println("Notifying to the Typetalk...");
Expand All @@ -69,16 +60,18 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
if (credential == null) {
throw new IllegalStateException("Credential is not found.");
}

Typetalk typetalk = new Typetalk(credential.getClientId(), credential.getClientSecret());

String message = makeMessage(build, TypetalkResult.convert(build), rootUrl);
Long topicId = Long.valueOf(topicNumber);
typetalk.postMessage(topicId, message);

return true;
}

private String makeMessage(AbstractBuild<?, ?> build, String buildSummary, String rootUrl) {
private String makeMessage(AbstractBuild<?, ?> build, TypetalkResult typetalkResult, String rootUrl) {
final StringBuilder message = new StringBuilder();
message.append(buildSummary);
message.append(typetalkResult);
message.append(" [ ");
message.append(build.getProject().getDisplayName());
message.append(" ]");
Expand All @@ -88,38 +81,13 @@ private String makeMessage(AbstractBuild<?, ?> build, String buildSummary, Strin
return message.toString();
}

/**
* ビルドの要約メッセージを取得する。
*
* @param build
* ビルド
* @return 通知対象ならばビルドの要約メッセージ、通知対象でないならば {@code null}
*/
private String toBuildSummary(AbstractBuild<?, ?> build) {
// ビルドが成功に戻った場合
if (build.getResult().equals(Result.SUCCESS)
&& build.getPreviousBuild() != null
&& build.getPreviousBuild().getResult().isWorseThan(Result.SUCCESS)) {
return ":smiley: Build recovered.";
}

// ビルド成功で "ビルドが成功した場合も通知する" がオフの場合、通知しない
if (build.getResult().equals(Result.SUCCESS) && notifyWhenSuccess == false) {
return null;
}

if (build.getResult().equals(Result.ABORTED)) {
return ":astonished: Build aborted.";
} else if (build.getResult().equals(Result.NOT_BUILT)) {
return ":astonished: Not built.";
} else if (build.getResult().equals(Result.FAILURE)) {
return ":rage: Build failure.";
} else if (build.getResult().equals(Result.UNSTABLE)) {
return ":cry: Build unstable.";
} else if (build.getResult().equals(Result.SUCCESS)) {
return ":smiley: Build successful.";
private boolean successFromPreviousBuild(AbstractBuild<?, ?> build) {
if (build.getPreviousBuild() == null) {
return build.getResult().equals(Result.SUCCESS);
} else {
return build.getResult().equals(Result.SUCCESS)
&& build.getPreviousBuild().getResult().equals(Result.SUCCESS);
}
throw new RuntimeException("Unknown build result.");
}

@Override
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/org/jenkinsci/plugins/typetalk/TypetalkResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.jenkinsci.plugins.typetalk;

import hudson.model.AbstractBuild;
import hudson.model.Result;

public class TypetalkResult {

public enum Emoji {
ASTONISHED(":astonished:"),
RAGE(":rage:"),
CRY(":cry:"),
SMILEY(":smiley:");

private String symbol;

Emoji(String symbol) {
this.symbol = symbol;
}
}

private Emoji emoji;
private String message;

public Emoji getEmoji() {
return emoji;
}

public String getMessage() {
return message;
}

public TypetalkResult(Emoji emoji, String message) {
this.emoji = emoji;
this.message = message;
}

public static TypetalkResult convert(AbstractBuild<?, ?> build) {
if (build.getResult().equals(Result.ABORTED)) {
return new TypetalkResult(Emoji.ASTONISHED, "Build aborted");
} else if (build.getResult().equals(Result.NOT_BUILT)) {
return new TypetalkResult(Emoji.ASTONISHED, "Not built");
} else if (build.getResult().equals(Result.FAILURE)) {
return new TypetalkResult(Emoji.RAGE, "Build failure");
} else if (build.getResult().equals(Result.UNSTABLE)) {
return new TypetalkResult(Emoji.CRY, "Build unstable");
} else if (build.getResult().equals(Result.SUCCESS)) {
if (recoverSuccess(build)) {
return new TypetalkResult(Emoji.SMILEY, "Build recovery");
} else {
return new TypetalkResult(Emoji.SMILEY, "Build success");
}
}

throw new IllegalArgumentException("Unknown build result.");
}

private static boolean recoverSuccess(AbstractBuild<?, ?> build) {
if (build.getPreviousBuild() == null) {
return false;
} else {
return build.getResult().equals(Result.SUCCESS)
&& build.getPreviousBuild().getResult().isWorseThan(Result.SUCCESS);
}
}

@Override
public String toString() {
return emoji.symbol + " " + message;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.jenkinsci.plugins.typetalk

import hudson.model.AbstractBuild
import hudson.model.Result
import spock.lang.Specification
import spock.lang.Unroll

class TypetalkResultSpec extends Specification {

@Unroll
def convert() {
setup:
def build = makeMockBuild(result, previousResult)

when:
def typetalkResult = TypetalkResult.convert(build)

then:
typetalkResult.emoji == emoji
typetalkResult.message.contains(message)

where:
previousResult | result || emoji | message
Result.SUCCESS | Result.SUCCESS || TypetalkResult.Emoji.SMILEY | 'success'
Result.SUCCESS | Result.UNSTABLE || TypetalkResult.Emoji.CRY | 'unstable'
Result.SUCCESS | Result.FAILURE || TypetalkResult.Emoji.RAGE | 'failure'
Result.SUCCESS | Result.ABORTED || TypetalkResult.Emoji.ASTONISHED | 'aborted'
Result.SUCCESS | Result.NOT_BUILT || TypetalkResult.Emoji.ASTONISHED | 'Not built'

Result.FAILURE | Result.SUCCESS || TypetalkResult.Emoji.SMILEY | 'recovery'
Result.FAILURE | Result.UNSTABLE || TypetalkResult.Emoji.CRY | 'unstable'
Result.FAILURE | Result.FAILURE || TypetalkResult.Emoji.RAGE | 'failure'
Result.FAILURE | Result.ABORTED || TypetalkResult.Emoji.ASTONISHED | 'aborted'
Result.FAILURE | Result.NOT_BUILT || TypetalkResult.Emoji.ASTONISHED | 'Not built'
}

def makeMockBuild(Result result, Result previousResult) {
def build = Mock(AbstractBuild)

build.result >> result
build.previousBuild >> {
def previousBuild = Mock(AbstractBuild)
previousBuild.result >> previousResult

return previousBuild
}

return build
}
}

0 comments on commit 9fd1dc4

Please sign in to comment.