Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use slack-webhook library #35

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
target
teamcity-slack-integration-server/out
teamcity-slack-integration-server/target
*.class

Expand Down
4 changes: 4 additions & 0 deletions teamcity-slack-integration-server/build.gradle
Expand Up @@ -4,12 +4,16 @@ plugins {
id "com.github.rodm.teamcity-server" version "0.9.1"
}

sourceCompatibility = 1.7
targetCompatibility = 1.7

repositories {
jcenter()
}

dependencies {
compile 'com.google.code.gson:gson:1.7.1'
compile 'net.gpedro.integrations.slack:slack-webhook:1.2.1'
}

group = 'com.enlivenhq.teamcity'
Expand Down
5 changes: 5 additions & 0 deletions teamcity-slack-integration-server/pom.xml
Expand Up @@ -24,5 +24,10 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>net.gpedro.integrations.slack</groupId>
<artifactId>slack-webhook</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
</project>
@@ -1,32 +1,25 @@
package com.enlivenhq.slack;

import com.enlivenhq.teamcity.MessageFactory;
import com.enlivenhq.teamcity.SlackNotificator;
import com.enlivenhq.teamcity.SlackPayload;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import jetbrains.buildServer.Build;
import jetbrains.buildServer.serverSide.TeamCityProperties;
import jetbrains.buildServer.web.util.WebUtil;
import net.gpedro.integrations.slack.SlackApi;
import net.gpedro.integrations.slack.SlackMessage;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;

public class SlackWrapper
{
public static final GsonBuilder GSON_BUILDER = new GsonBuilder().excludeFieldsWithoutExposeAnnotation();
public class SlackWrapper {
private static final Logger LOG = Logger.getLogger(SlackNotificator.class);
protected String slackUrl;

protected String username;
private String slackUrl;

private String username;

protected String channel;
private String channel;

protected String serverUrl;
private String serverUrl;

protected Boolean useAttachment;
Boolean useAttachment;

public SlackWrapper () {
this.useAttachment = TeamCityProperties.getBooleanOrTrue("teamcity.notification.slack.useAttachment");
Expand All @@ -36,104 +29,41 @@ public SlackWrapper (Boolean useAttachment) {
this.useAttachment = useAttachment;
}

public String send(String project, String build, String branch, String statusText, String statusColor, Build bt) throws IOException
{
String formattedPayload = getFormattedPayload(project, build, branch, statusText, statusColor, bt.getBuildTypeExternalId(), bt.getBuildId());
LOG.debug(formattedPayload);

URL url = new URL(this.getSlackUrl());
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();

httpsURLConnection.setRequestMethod("POST");
httpsURLConnection.setRequestProperty("User-Agent", "Enliven");
httpsURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
httpsURLConnection.setDoOutput(true);

DataOutputStream dataOutputStream = new DataOutputStream(
httpsURLConnection.getOutputStream()
);

dataOutputStream.writeBytes(formattedPayload);
dataOutputStream.flush();
dataOutputStream.close();

InputStream inputStream;
String responseBody = "";

try {
inputStream = httpsURLConnection.getInputStream();
}
catch (IOException e) {
responseBody = e.getMessage();
inputStream = httpsURLConnection.getErrorStream();
if (inputStream != null) {
responseBody += ": ";
responseBody = getResponseBody(inputStream, responseBody);
}
throw new IOException(responseBody);
}

return getResponseBody(inputStream, responseBody);
}

@NotNull
public String getFormattedPayload(String project, String build, String branch, String statusText, String statusColor, String btId, long buildId) {
Gson gson = GSON_BUILDER.create();

SlackPayload slackPayload = new SlackPayload(project, build, branch, statusText, statusColor, btId, buildId, WebUtil.escapeUrlForQuotes(getServerUrl()));
slackPayload.setChannel(getChannel());
slackPayload.setUsername(getUsername());
slackPayload.setUseAttachments(this.useAttachment);

return gson.toJson(slackPayload);
}

private String getResponseBody(InputStream inputStream, String responseBody) throws IOException {
String line;

BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream)
);

while ((line = bufferedReader.readLine()) != null) {
responseBody += line + "\n";
}
public void send(String project, String build, String branch, String statusText, String statusColor, Build bt) {
SlackMessage message = MessageFactory.createBuildStatusMessage(
getChannel(), getUsername(), project, build, branch, statusText, statusColor,
bt.getBuildTypeExternalId(), bt.getBuildId(), getServerUrl(), useAttachment);
LOG.debug(message.toString());

bufferedReader.close();
return responseBody;
SlackApi slackClient = new SlackApi(getSlackUrl());
slackClient.call(message);
}

public void setSlackUrl(String slackUrl)
{
public void setSlackUrl(String slackUrl) {
this.slackUrl = slackUrl;
}

public String getSlackUrl()
{
private String getSlackUrl() {
return this.slackUrl;
}

public void setUsername(String username)
{
public void setUsername(String username) {
this.username = username;
}

public String getUsername()
{
private String getUsername() {
return this.username;
}

public void setChannel(String channel)
{
public void setChannel(String channel) {
this.channel = channel;
}

public String getChannel()
{
private String getChannel() {
return this.channel;
}

public String getServerUrl() {
private String getServerUrl() {
return serverUrl;
}

Expand Down
@@ -0,0 +1,66 @@
package com.enlivenhq.teamcity;

import net.gpedro.integrations.slack.SlackAttachment;
import net.gpedro.integrations.slack.SlackField;
import net.gpedro.integrations.slack.SlackMessage;

/**
* Generates {@link net.gpedro.integrations.slack.SlackMessage} instances.
* <p>
* The messages are appropriate for the given TeamCity data.
*/
public class MessageFactory {

public static SlackMessage createBuildStatusMessage(
String channel, String username, String project, String build, String branch, String statusText,
String statusColor, String btId, long buildId, String serverUrl, boolean useAttachments) {
project = escape(project);
build = escape(build);
branch = escape(branch);
statusText = escape(escapeNewline(statusText));
btId = escape(btId);

String escapedBranch = branch.length() > 0 ? " [" + branch + "]" : "";

statusText = "<" + serverUrl + "/viewLog.html?buildId=" + buildId + "&buildTypeId=" + btId + "|" + statusText + ">";

String statusEmoji = statusColor.equals("danger") ? ":x: " : statusColor.equals("warning") ? "" : ":white_check_mark: ";

String payloadText = statusEmoji + project + escapedBranch + " #" + build + " " + statusText;

SlackMessage message = new SlackMessage(channel, username, payloadText);

if (useAttachments) {
SlackAttachment attachment = new SlackAttachment();
attachment.setColor(statusColor);
attachment.setPretext("Build Status");
attachment.setFallback(payloadText);


SlackField attachmentProject = new SlackField().setTitle("Project").setValue(project).setShorten(false);
SlackField attachmentBuild = new SlackField().setTitle("Build").setValue(build).setShorten(true);
SlackField attachmentStatus = new SlackField().setTitle("Status").setValue(statusText).setShorten(false);

attachment.addFields(attachmentProject);
attachment.addFields(attachmentBuild);
attachment.addFields(attachmentStatus);

SlackField attachmentBranch;
if (branch.length() > 0) {
attachmentBranch = new SlackField().setTitle("Branch").setValue(branch).setShorten(false);
attachment.addFields(attachmentBranch);
}

message.addAttachments(attachment);
}
return message;
}

private static String escape(String s) {
return s.replace("<", "&lt;").replace(">", "&gt;");
}

private static String escapeNewline(String s) {
return s.replace("\n", "\\n");
}
}
Expand Up @@ -6,7 +6,16 @@
import jetbrains.buildServer.notification.NotificatorRegistry;
import jetbrains.buildServer.responsibility.ResponsibilityEntry;
import jetbrains.buildServer.responsibility.TestNameResponsibilityEntry;
import jetbrains.buildServer.serverSide.*;
import jetbrains.buildServer.serverSide.Branch;
import jetbrains.buildServer.serverSide.SBuild;
import jetbrains.buildServer.serverSide.SBuildServer;
import jetbrains.buildServer.serverSide.SBuildType;
import jetbrains.buildServer.serverSide.SProject;
import jetbrains.buildServer.serverSide.SRunningBuild;
import jetbrains.buildServer.serverSide.STest;
import jetbrains.buildServer.serverSide.UserForm;
import jetbrains.buildServer.serverSide.UserPropertyInfo;
import jetbrains.buildServer.serverSide.UserPropertyValidator;
import jetbrains.buildServer.serverSide.mute.MuteInfo;
import jetbrains.buildServer.serverSide.problems.BuildProblemInfo;
import jetbrains.buildServer.tests.TestName;
Expand All @@ -18,7 +27,6 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
Expand Down Expand Up @@ -139,13 +147,13 @@ private void registerNotificatorAndUserProperties(NotificatorRegistry notificato
}

private ArrayList<UserPropertyInfo> getUserPropertyInfosList() {
ArrayList<UserPropertyInfo> userPropertyInfos = new ArrayList<UserPropertyInfo>();
ArrayList<UserPropertyInfo> userPropertyInfos = new ArrayList<>();

UserPropertyValidator verboseValidator = new UserPropertyValidator() {
@Nullable
public String validate(@NotNull String s, @Nullable SUser sUser, @NotNull UserForm userForm) {
String sUpper = s.toUpperCase();
Set<String> validValues = new HashSet<String>();
Set<String> validValues = new HashSet<>();
validValues.add("TRUE");
validValues.add("FALSE");
validValues.add("YES");
Expand All @@ -161,20 +169,15 @@ public String validate(@NotNull String s, @Nullable SUser sUser, @NotNull UserFo
userPropertyInfos.add(new UserPropertyInfo(slackChannelKey, "#channel or @name"));
userPropertyInfos.add(new UserPropertyInfo(slackUsernameKey, "Bot name"));
userPropertyInfos.add(new UserPropertyInfo(slackUrlKey, "Webhook URL"));
userPropertyInfos.add(new UserPropertyInfo(slackVerboseKey, "Verbose Messages", "True", verboseValidator));
userPropertyInfos.add(new UserPropertyInfo(slackVerboseKey, "Verbose Messages", "True or False", verboseValidator));

return userPropertyInfos;
}

private void sendNotification(String project, String build, String statusText, String statusColor, Set<SUser> users, Build bt) {
for (SUser user : users) {
SlackWrapper slackWrapper = getSlackWrapperWithUser(user);
try {
slackWrapper.send(project, build, getBranch((SBuild)bt), statusText, statusColor, bt);
}
catch (IOException e) {
log.error(e.getMessage());
}
slackWrapper.send(project, build, getBranch((SBuild)bt), statusText, statusColor, bt);
}
}

Expand Down Expand Up @@ -212,7 +215,7 @@ private SlackWrapper constructSlackWrapper(String channel, String username, Stri

private String getBranch(SBuild build) {
Branch branch = build.getBranch();
if (branch != null && branch.getName() != "<default>") {
if (branch != null && !branch.getName().equals("<default>")) {
return branch.getDisplayName();
} else {
return "";
Expand Down