開發Jenkins Line Notify Plugin(進階篇)

姜志民 2019/08/12 09:14:20
198

一、前言

Jenkins有豐富的plugins資源提供開發人員使用,但有時候plugin提供的功能並不能完全符合自己的需求,這時候開發人員就必須自行開發符合需求的plugin。

這次將透過開發LINE Notify功能的plugin,來了解plugin開發步驟。

 

二、運作流程

這個Plunin可以協助每個專案完成建置編譯時,再透過LINE Notify服務通知相關人員,通知建置編譯是完成或是失敗的訊息。讓整個團隊人員隨時都能知道專案的建置編譯狀況。

 

 

三、申請LINE Notify權杖

a.進入https://notify-bot.line.me/ => 「登入」。

 

b.輸入自己的LINE帳號登入。

 

c.進入「個人頁面」。

 

d.點擊「發行權杖」。

 

e.輸入權杖名稱並選擇要接收的聊天室,在按下「發行」。

 

f.將權杖記下來,後續會使用到。

 

四、Maven下載

a.到https://maven.apache.org/,下載Maven 3.6.1。

b.將Maven 3.6.1解壓所放置到C:\Program Files目錄下。

 

五、建立Jenkins Plugin專案

a.在「命令提示字元」下,執行"C:\Program Files\apache-maven-3.6.1\bin\mvn" -U archetype:generate -Dfilter="io.jenkins.archetypes:"指令,並選擇「1」建立空白專案。

 

b.number選擇「5」,’artifactId’輸入「lineNotify」,最後按下「y」。

 

c.成功建立空白專案,畫面如下。

 

六、開發Jenkins Line Notify Plugin 

a.使用Eclipse將空白專案匯入,匯入後畫面如下。

 

b.在package io.jenkins.plugins下建立LineNotify.java,處理將訊息傳送到LINE,程式碼如下。

package io.jenkins.plugins;

import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Pattern;

public class LineNotify {

	private static final String strEndpoint = "https://notify-api.line.me/api/notify";
	public static final String wrap = "%0D%0A";

	public boolean sendMessage(String token, String message, boolean encoded) {
		message = replaceProcess(message);
		if (!encoded) {
			try {
				message = URLEncoder.encode(message, "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		return callEvent(token, message);
	}

	private boolean callEvent(String token, String message) {
		boolean result = false;
		try {

			String strUrl = strEndpoint;
			URL url = new URL(strUrl);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.addRequestProperty("Authorization", "Bearer " + token);
			connection.setRequestMethod("POST");
			connection.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			connection.setDoOutput(true);
			String parameterString = new String("message=" + message);
			PrintWriter printWriter = new PrintWriter(connection.getOutputStream());
			printWriter.print(parameterString);
			printWriter.close();
			connection.connect();

			int statusCode = connection.getResponseCode();
			if (statusCode == 200) {
				result = true;
			} else {
				throw new Exception("Error:(StatusCode)" + statusCode + ", " + connection.getResponseMessage());
			}
			connection.disconnect();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}

	private String replaceProcess(String txt) {
		txt = replaceAllRegex(txt, "\\\\", "¥"); // \
		return txt;
	}

	private String replaceAllRegex(String value, String regex, String replacement) {
		if (value == null || value.length() == 0 || regex == null || regex.length() == 0 || replacement == null)
			return "";
		return Pattern.compile(regex).matcher(value).replaceAll(replacement);
	}
}

 

c. 在package io.jenkins.plugins下建立LineNotifyNotifier.java,Jenkins會執行此物件來進行LINE Notify動作,程式碼如下:

package io.jenkins.plugins;

import java.io.IOException;
import java.net.URLEncoder;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractProject;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import jenkins.tasks.SimpleBuildStep;

public class LineNotifyNotifier extends Notifier implements SimpleBuildStep {

	private String token;

	private String remark;

	@DataBoundConstructor
	public LineNotifyNotifier(String token) {
		this.token = token;
	}

	@DataBoundSetter
	public void setRemark(String remark) {
		this.remark = remark;
	}

	public String getToken() {
		return token;
	}

	public String getRemark() {
		return remark;
	}

	@Override
	public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener)
			throws InterruptedException, IOException {
		// TODO Auto-generated method stub
		LineNotify l = new LineNotify();
		StringBuffer message = new StringBuffer();
		message.append(LineNotify.wrap + LineNotify.wrap);

		message.append(
				URLEncoder.encode("專案名稱:" + ("".equals(run.getParent().getDisplayName()) ? run.getParent().getName()
						: run.getParent().getDisplayName()), "UTF-8"));

		message.append(LineNotify.wrap + LineNotify.wrap);

		message.append(URLEncoder.encode("狀態:" + (run.getResult() == null ? "" : run.getResult().toString()), "UTF-8"));

		message.append(LineNotify.wrap + LineNotify.wrap);

		message.append(URLEncoder.encode("建置歷程:" + run.getNumber(), "UTF-8"));

		message.append(LineNotify.wrap + LineNotify.wrap);

		long diff = System.currentTimeMillis() - run.getStartTimeInMillis();

		long minutes = diff / (1000 * 60);
		long seconds = (diff / 1000) - (minutes * 60);

		message.append(URLEncoder.encode("建置時間:" + minutes + "分" + seconds + "秒", "UTF-8"));

		message.append(LineNotify.wrap + LineNotify.wrap);

		message.append(URLEncoder.encode("備註:" + remark, "UTF-8"));

		l.sendMessage(token, message.toString(), true);
	}

	@Extension
	public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {

		@Override
		public boolean isApplicable(@SuppressWarnings("rawtypes") Class<? extends AbstractProject> jobType) {

			return true;
		}

		@Override
		public String getDisplayName() {
			return "LINE Notify";
		}
	}

	@Override
	public BuildStepMonitor getRequiredMonitorService() {
		return BuildStepMonitor.NONE;
	}

}

 

七、建立UI元件

a.在resources目錄下建立io\jenkins\plugins\LineNotifyNotifier目錄,如下圖。

 

b.在io\jenkins\plugins\LineNotifyNotifier目錄下,建立一個config.jelly檔案,程式碼如下:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
	<f:entry title="存取權杖" field="token">
		<f:textbox />
	</f:entry>
	<f:entry title="備註" field="remark">
		<f:textbox />
	</f:entry>
</j:jelly>

 

八、執行Jenkins Line Notify Plugin

a.在「lineNotify」上按右鍵 => 「Run as」=> 「Run Configurations」。

 

b.執行參數設定如下:

 

 

c.等待出現「資訊: Jenkins is fully up and running」,如下圖。

 

d.在瀏覽器中,進入http://127.0.0.1:8080/jenkins/如下圖,進入「新增作業」。

 

e.輸入相關作業資訊。

 

f.進入「建置後動作」=>「新增建置後動作」=>「LINE Notify」。

 

g.輸入權杖與備註後,按「儲存」。

 

h.按下「馬上建置」,就可以收到LINE Notify。

 

九、通知畫面

筆者的LINE就會收到訊息如下。

十、封裝成Jenkins Plugin安裝檔

a.設定如下,在按下「Run」:

 

b.在「target」目錄下可以找到封裝完成「lineNotify.hpi」檔案。

十、安裝Jenkins Plugin檔案

在「管理 Jenkins」->「外掛程式管理」內,來上傳剛剛完成的lineNotify.hpi檔案。

 

姜志民