1. 記事一覧 >
  2. ブログ記事
category logo

GitLab,Wekan→Rocket.Chat→SlackのWebHook

(更新) (公開)

はじめに

先日
・GitLab
・Wekan
・Rocket.Chat
をローカルの環境にインストールしました。

※インストールについては、下記別記事を参照してください。
「Ubuntu 20.04.2.0にGitLabをインストール」
「CentOS8にwekanをインストール(ソースからビルド編)」
「CentOS8にRocket.Chatをインストール」

この環境は自宅や外出時のスマホなどのインターネットから直接見られません。
そこで、インターネットからチャットの内容、GitLab,Wekanのアクティビティについて確認できるようWebHookを利用して、以下の環境を構築しました。



Slackはインターネットのビジネスチャットサービスで、10000通まで無料です。(2021/06現在)
Slackについては、WebHookの手順以外、今回解説しません。

【 WebHook 】

「WebHook」とは、データ更新などのイベントが発生したら、外部のアプリやサービスに通知を送り、連携する仕組みのことです。


SlackにIncoming WebHookを設定
Rocket.ChatにOutgoing WebHookを設定
Rocket.ChatにIncoming WebHook(GitLab用)を設定
GitLabにOutgoing WebHookを設定
Rocket.ChatにIncoming WebHook(Wekan用)を設定
WekanにOutgoing WebHookを設定
まで全手順をご紹介していきます。


SlackにIncoming WebHookを設定


Slackにログインして、Slackのアプリケーション追加ページを開きます。
https://slack.com/apps

「Webhook」と入力して、「Incoming WebHook」を選択します。

「Slackに追加」をクリックします。

チャンネルを追加します。
→ここで選択したチャンネルがRocket.Chatから受信するチャンネルになります。

「Incoming WebHook インテグレーションの追加」をクリックします。

ここで、「Webhook URL」をコピーしておきます。

「設定を保存する」をクリックします。

以上で、Slackの設定は完了です。


Rocket.ChatにOutgoing WebHookを設定


Rocket.Chatに管理者でログイン後、ユーザーのアイコンをクリックして、「管理」をクリックします。

「サービス連携」をクリックします。

「+New」をクリックし、「Outgoing」を選択します。


「イベントトリガー」は、"メッセージが送信されました"とし、Rocket.Chatでメッセージが書き込まれるたびにWebHookが作動するようにします。
「名前」は、"Slack"とします。
Rocket.Chatの#generalチャンネルからSlackの #rocketchat チャンネルへ伝播したいので、チャンネルは、 #general に設定します。
「URLs」のところは、先ほど、Slackの設定でコピーしたWebhook URLを貼り付けます。
「投稿ユーザー」は、Rocket.Chatで登録されているユーザー名を入力します。

「トークン」は、今回特に意味は無いため、入力されたままにします。
Scriptのところに、以下の内容のスクリプトを貼り付けます。


Script

クリックしてソースを表示
class Script {
  /**
   * @params {object} request
   */
  prepare_outgoing_request({ request }) {
    // request.params            {object}
    // request.method            {string}
    // request.url               {string}
    // request.auth              {string}
    // request.headers           {object}
    // request.data.token        {string}
    // request.data.channel_id   {string}
    // request.data.channel_name {string}
    // request.data.timestamp    {date}
    // request.data.user_id      {string}
    // request.data.user_name    {string}
    // request.data.text         {string}
    // request.data.trigger_word {string}
    return {
      url: request.url,
      headers: request.headers,
      method: 'POST',
      data: {
        channel: '#rocketchat',
        username: request.data.alias
          ? request.data.alias
          : request.data.user_name,
        text: request.data.text,
        icon_emoji: ':ghost:',
      },
    };
  }

  /**
   * @params {object} request, response
   */
  process_outgoing_response({ request, response }) {
    // request              {object} - the object returned by prepare_outgoing_request

    // response.error       {object}
    // response.status_code {integer}
    // response.content     {object}
    // response.content_raw {string/object}
    // response.headers     {object}

    // Return false will abort the response
    return false;
  }
}

prepare_outgoing_requestreturnのところのtext:message:とすると、Rocket.Chatに投稿されて無限ループしました。Rocket.Chatに投稿→WebHook発動→WebHookからRocket.Chatに投稿→Rocket.Chatに投稿...となってしまいました。


Scriptの
channelは、伝播させたいSlackのチャンネル名
usernameは、Slackに投稿するユーザー名
textは、Slackに投稿する内容
icon_emojiは、Slackに表示されるアイコンを絵文字コードで指定
の意味になります。

      data: {
        channel: '#rocketchat',
        username: request.data.alias
          ? request.data.alias
          : request.data.user_name,
        text: request.data.text,
        icon_emoji: ':ghost:',
      },

icon_emoji: の絵文字コードですが、https://www.webfx.com/tools/emoji-cheat-sheet/ 等で分かりますので、:ghost:に限らず、:smile:などに変更もできます。


「有効」、「スクリプトを有効にする」スイッチをオンにして、保存ボタンをクリックします。


以上で、Rocket.Chat→Slackの設定は完了です。


Rocket.ChatにIncoming WebHook(GitLab用)を設定


Rocket.Chatに管理者でログイン後、ユーザーのアイコンをクリックして、「管理」をクリックします。
「サービス連携」をクリックします。
「Incoming」を選択して、「+New」をクリックします。

「名前」は、「GitLab」とし、投稿先チャンネルは、 #general とします。
「投稿ユーザー」は、Rocket.Chatで登録されているユーザー名を入力します。
「エイリアス」は、ユーザー名の前に表示されるのですが、今回スクリプトを登録するため、反映されません。 「絵文字」は、アバターの画像になります。https://www.webfx.com/tools/emoji-cheat-sheet/ 等で調べて、絵文字コードを入力します。今回スクリプトを登録するため、通常、GitLabのユーザーアイコンが表示されます。

Scriptのところに、以下の内容のスクリプトを貼り付けます。


Script

クリックしてソースを表示
/* eslint no-console:0, max-len:0, complexity:0 */
// see https://gitlab.com/help/web_hooks/web_hooks for full json posted by GitLab
const MENTION_ALL_ALLOWED = false; // <- check that bot permission 'mention-all' are activated in rocketchat before passing this to true.
const NOTIF_COLOR = '#6498CC';
const IGNORE_CONFIDENTIAL = true;
const IGNORE_UNKNOWN_EVENTS = false;
const IGNORE_ERROR_MESSAGES = false;
const USE_ROCKETCHAT_AVATAR = false;
const DEFAULT_AVATAR = null; // <- null means use the avatar from settings if no other is available
const STATUSES_COLORS = {
	success: '#2faa60',
	pending: '#e75e40',
	failed: '#d22852',
	canceled: '#5c5c5c',
	created: '#ffc107',
	running: '#607d8b',
};
const ACTION_VERBS = {
	create: 'created',
	destroy: 'removed',
	update: 'updated',
	rename: 'renamed',
	transfer: 'transferred',
	add: 'added',
	remove: 'removed',
};
const ATTACHMENT_TITLE_SIZE = 10; // Put 0 here to have not title as in previous versions
const refParser = (ref) => ref.replace(/^refs\/(?:tags|heads)\/(.+)$/, '$1');
const displayName = (name) => (name && name.toLowerCase().replace(/\s+/g, '.').normalize('NFD').replace(/[\u0300-\u036f]/g, ''));
const atName = (user) => (user && user.name ? '@' + displayName(user.name) : '');
const makeAttachment = (author, text, timestamp, color) => {
	const currentTime = (new Date()).toISOString();
	const attachment = {
		author_name: author ? displayName(author.name) : '',
		author_icon: author ? author.avatar_url : '',
		ts: timestamp || currentTime,
		text,
		color: color || NOTIF_COLOR
	};
	if (ATTACHMENT_TITLE_SIZE > 0) {
		attachment.title = text.substring(0, ATTACHMENT_TITLE_SIZE) + '...';
	}

	return attachment;
};
const pushUniq = (array, val) => ~array.indexOf(val) || array.push(val); // eslint-disable-line

class Script { // eslint-disable-line
	process_incoming_request({ request }) {
		try {
			let result = null;
			const channel = request.url.query.channel;
			const event = request.headers['x-gitlab-event'];
			switch (event) {
				case 'Push Hook':
					result = this.pushEvent(request.content);
					break;
				case 'Merge Request Hook':
					result = this.mergeRequestEvent(request.content);
					break;
				case 'Note Hook':
					result = this.commentEvent(request.content);
					break;
				case 'Confidential Issue Hook':
				case 'Issue Hook':
					result = this.issueEvent(request.content, event);
					break;
				case 'Tag Push Hook':
					result = this.tagEvent(request.content);
					break;
				case 'Pipeline Hook':
				case 'Pipeline Event':
					result = this.pipelineEvent(request.content);
					break;
				case 'Build Hook': // GitLab < 9.3.0
				case 'Job Hook': // GitLab >= 9.3.0
					result = this.buildEvent(request.content);
					break;
				case 'Wiki Page Hook':
					result = this.wikiEvent(request.content);
					break;
				case 'System Hook':
					result = this.systemEvent(request.content);
					break;
				default:
					if (IGNORE_UNKNOWN_EVENTS) {
						console.log('gitlabevent unknown', event);
						return { error: { success: false, message: `unknonwn event ${event}` } };
					}
					result = IGNORE_UNKNOWN_EVENTS ? null : this.unknownEvent(request, event);
					break;
			}
			if (result && result.content && channel) {
				result.content.channel = '#' + channel;
			}
			return result;
		} catch (e) {
			console.log('gitlabevent error', e);
			return this.createErrorChatMessage(e);
		}
	}

	createErrorChatMessage(error) {
		if (IGNORE_ERROR_MESSAGES) {
			return { error: { success: false, message: `gitlabevent error: ${error.message}` } };
		}
		return {
			content: {
				username: 'Rocket.Cat ErrorHandler',
				//text: 'Error occured while parsing an incoming webhook request. Details attached.',
				text:
					'Error occured while parsing an incoming webhook request. Details attached.\n' +
					`Error: '${error}', \n Message: '${error.message}', \n Stack: '${error.stack}'`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : DEFAULT_AVATAR,
				// attachments: [
				// 	{
				// 		text: `Error: '${error}', \n Message: '${error.message}', \n Stack: '${error.stack}'`,
				// 		color: NOTIF_COLOR
				// 	}
				// ]
			}
		};
	}

	unknownEvent(data, event) {
		const user_avatar = data.user ? data.user.avatar_url : (data.user_avatar || DEFAULT_AVATAR);
		return {
			content: {
				username: data.user ? data.user.name : (data.user_name || 'Unknown user'),
				//text: `Unknown event '${event}' occured. Data attached.`,
				text: `Unknown event '${event}' occured. Data attached.\n${JSON.stringify(
					data,
					null,
					4
				)}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : user_avatar,
				// attachments: [
				// 	{
				// 		text: `${JSON.stringify(data, null, 4)}`,
				// 		color: NOTIF_COLOR
				// 	}
				// ]
			}
		};
	}
	issueEvent(data, event) {
		if (event === 'Confidential Issue Hook' && IGNORE_CONFIDENTIAL) {
			return false;
		}
		const project = data.project || data.repository;
		const state = data.object_attributes.state;
		const action = data.object_attributes.action;
		const time = data.object_attributes.updated_at;
		const project_avatar = project.avatar_url || data.user.avatar_url || DEFAULT_AVATAR;
		let user_action = state;
		let assigned = '';

		if (action === 'update') {
			user_action = 'updated';
		}

		if (data.assignee) {
			assigned = `*Assigned to*: @${data.assignee.username}\n`;
		}

		return {
			content: {
				username: 'gitlab/' + project.name,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : project_avatar,
				// text: (data.assignee && data.assignee.name !== data.user.name) ? atName(data.assignee) : '',
				text:
					`*${data.user ? displayName(data.user.name) : ''}*\n` +
					'担当者:' +
					(data.assignee && data.assignee.name !== data.user.name
						? atName(data.assignee)
						: '無し') +
					`\n${user_action} an issue _${data.object_attributes.title}_ on ${project.name}.
					*Description:* ${data.object_attributes.description}.
					${assigned}
					See: ${data.object_attributes.url}`,
				// 				attachments: [
				// 					makeAttachment(
				// 						data.user,
				// 						`${user_action} an issue _${data.object_attributes.title}_ on ${project.name}.
				// *Description:* ${data.object_attributes.description}.
				// ${assigned}
				// See: ${data.object_attributes.url}`,
				// 						time
				// 					)
				// 				]
			}
		};
	}

	commentEvent(data) {
		const project = data.project || data.repository;
		const comment = data.object_attributes;
		const user = data.user;
		const avatar = project.avatar_url || user.avatar_url || DEFAULT_AVATAR;
		const at = [];
		let text;
		if (data.merge_request) {
			const mr = data.merge_request;
			const lastCommitAuthor = mr.last_commit && mr.last_commit.author;
			if (mr.assignee && mr.assignee.name !== user.name) {
				at.push(atName(mr.assignee));
			}
			if (lastCommitAuthor && lastCommitAuthor.name !== user.name) {
				pushUniq(at, atName(lastCommitAuthor));
			}
			text = `commented on MR [#${mr.id} ${mr.title}](${comment.url})`;
		} else if (data.commit) {
			const commit = data.commit;
			const message = commit.message.replace(/\n[^\s\S]+/, '...').replace(/\n$/, '');
			if (commit.author && commit.author.name !== user.name) {
				at.push(atName(commit.author));
			}
			text = `commented on commit [${commit.id.slice(0, 8)} ${message}](${comment.url})`;
		} else if (data.issue) {
			const issue = data.issue;
			text = `commented on issue [#${issue.id} ${issue.title}](${comment.url})`;
		} else if (data.snippet) {
			const snippet = data.snippet;
			text = `commented on code snippet [#${snippet.id} ${snippet.title}](${comment.url})`;
		}
		return {
			content: {
				username: 'gitlab/' + project.name,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				//text: at.join(' '),
				text:
					`*${user ? displayName(user.name) : ''}*\n` +
					'担当者:' +
					at.join(' ') +
					`\n${text}\n${comment.note}`,
				// attachments: [
				// 	makeAttachment(user, `${text}\n${comment.note}`, comment.updated_at)
				// ]
			}
		};
	}

	mergeRequestEvent(data) {
		const user = data.user;
		const mr = data.object_attributes;
		const assignee = data.assignee;
		const avatar = mr.target.avatar_url || mr.source.avatar_url || user.avatar_url || DEFAULT_AVATAR;
		let at = [];

		if (mr.action === 'open' && assignee) {
			at.push(atName(assignee));
		} else if (mr.action === 'merge') {
			const lastCommitAuthor = mr.last_commit && mr.last_commit.author;
			if (assignee && assignee.username !== user.username) {
				at.push(atName(assignee));
			}
			if (lastCommitAuthor && lastCommitAuthor.username !== user.username) {
				pushUniq(at, atName(lastCommitAuthor));
			}
		} else if (mr.action === 'update' && assignee) {
			at.push(atName(assignee));
		}
		return {
			content: {
				username: `gitlab/${mr.target.name}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				//text: at.join(' '),
				text:
					`*${user ? displayName(user.name) : ''}*\n` +
					'担当者:' +
					at.join(' ') +
					`\n${mr.action} MR [#${mr.iid} ${mr.title}](${mr.url})\n${mr.source_branch} into ${mr.target_branch}`,
				// attachments: [
				// 	makeAttachment(user, `${mr.action} MR [#${mr.iid} ${mr.title}](${mr.url})\n${mr.source_branch} into ${mr.target_branch}`, mr.updated_at)
				// ]
			}
		};
	}

	pushEvent(data) {
		const project = data.project || data.repository;
		const web_url = project.web_url || project.homepage;
		const user = {
			name: data.user_name,
			avatar_url: data.user_avatar
		};
		const avatar = project.avatar_url || data.user_avatar || DEFAULT_AVATAR;
		// branch removal
		if (data.checkout_sha === null && !data.commits.length) {
			return {
				content: {
					text: `*${user ? displayName(user.name) : ''
						}*\n\`removed branch ${refParser(data.ref)} from [${project.name
						}](${web_url})\``,
					username: `gitlab/${project.name}`,
					icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
					// attachments: [
					// 	makeAttachment(user, `removed branch ${refParser(data.ref)} from [${project.name}](${web_url})`)
					// ]
				}
			};
		}
		// new branch
		if (data.before == 0) { // eslint-disable-line
			return {
				content: {
					text: `*${user ? displayName(user.name) : ''
						}*\n\`pushed new branch [${refParser(
							data.ref
						)}](${web_url}/commits/${refParser(data.ref)}) to [${project.name
						}](${web_url}), which is ${data.total_commits_count
						} commits ahead of master\``,
					username: `gitlab/${project.name}`,
					icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
					// attachments: [
					// 	makeAttachment(user, `pushed new branch [${refParser(data.ref)}](${web_url}/commits/${refParser(data.ref)}) to [${project.name}](${web_url}), which is ${data.total_commits_count} commits ahead of master`)
					// ]
				}
			};
		}
		return {
			content: {
				text:
					`*${user ? displayName(user.name) : ''}*\n\`pushed ${data.total_commits_count
					} commits to branch [${refParser(
						data.ref
					)}](${web_url}/commits/${refParser(data.ref)}) in [${project.name
					}](${web_url})\`\n\n` +
					data.commits
						.map(
							(commit) =>
								`  - ${new Date(commit.timestamp).toUTCString()} [${commit.id.slice(
									0,
									8
								)}](${commit.url}) by ${commit.author.name
								}: ${commit.message.replace(/\s*$/, '')}`
						)
						.join('\n'),
				username: `gitlab/${project.name}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				// attachments: [
				// 	makeAttachment(user, `pushed ${data.total_commits_count} commits to branch [${refParser(data.ref)}](${web_url}/commits/${refParser(data.ref)}) in [${project.name}](${web_url})`),
				// 	{
				// 		text: data.commits.map((commit) => `  - ${new Date(commit.timestamp).toUTCString()} [${commit.id.slice(0, 8)}](${commit.url}) by ${commit.author.name}: ${commit.message.replace(/\s*$/, '')}`).join('\n'),
				// 		color: NOTIF_COLOR
				// 	}
				// ]
			}
		};
	}

	tagEvent(data) {
		const project = data.project || data.repository;
		const web_url = project.web_url || project.homepage;
		const tag = refParser(data.ref);
		const user = {
			name: data.user_name,
			avatar_url: data.user_avatar
		};
		const avatar = project.avatar_url || data.user_avatar || DEFAULT_AVATAR;
		let message;
		if (data.checkout_sha === null) {
			message = `deleted tag [${tag}](${web_url}/tags/)`;
		} else {
			message = `pushed tag [${tag} ${data.checkout_sha.slice(0, 8)}](${web_url}/tags/${tag})`;
		}
		return {
			content: {
				username: `gitlab/${project.name}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				//text: MENTION_ALL_ALLOWED ? '@all' : '',
				text: `*${user ? displayName(user.name) : ''}*\n` + message,
				// text: MENTION_ALL_ALLOWED ? '@all' : '',
				// attachments: [
				// 	makeAttachment(user, message)
				// ]
			}
		};
	}

	pipelineEvent(data) {
		const project = data.project || data.repository;
		const commit = data.commit;
		const user = {
			name: data.user_name,
			avatar_url: data.user_avatar
		};
		const pipeline = data.object_attributes;
		const pipeline_time = pipeline.finished_at || pipeline.created_at;
		const avatar = project.avatar_url || data.user_avatar || DEFAULT_AVATAR;

		return {
			content: {
				username: `gitlab/${project.name}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				text: `*${user ? displayName(user.name) : ''}*\npipeline returned *${pipeline.status
					}* for commit [${commit.id.slice(0, 8)}](${commit.url}) made by *${commit.author.name
					}*`,
				// attachments: [
				// 	makeAttachment(user, `pipeline returned *${pipeline.status}* for commit [${commit.id.slice(0, 8)}](${commit.url}) made by *${commit.author.name}*`, pipeline_time, STATUSES_COLORS[pipeline.status])
				// ]
			}
		};
	}

	buildEvent(data) {
		const user = {
			name: data.user_name,
			avatar_url: data.user_avatar
		};

		return {
			content: {
				username: `gitlab/${data.repository.name}`,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : DEFAULT_AVATAR,
				text: `*${user ? displayName(user.name) : ''}*\nbuild named *${data.build_name
					}* returned *${data.build_status}* for [${data.project_name}](${data.repository.homepage
					})`,
				// attachments: [
				// 	makeAttachment(user, `build named *${data.build_name}* returned *${data.build_status}* for [${data.project_name}](${data.repository.homepage})`, null, STATUSES_COLORS[data.build_status])
				// ]
			}
		};
	}

	wikiPageTitle(wiki_page) {
		if (wiki_page.action === 'delete') {
			return wiki_page.title;
		}

		return `[${wiki_page.title}](${wiki_page.url})`;
	}

	wikiEvent(data) {
		const user_name = data.user.name;
		const project = data.project;
		const project_path = project.path_with_namespace;
		const wiki_page = data.object_attributes;
		const wiki_page_title = this.wikiPageTitle(wiki_page);
		const user_action = ACTION_VERBS[wiki_page.action] || 'modified';
		const avatar = project.avatar_url || data.user.avatar_url || DEFAULT_AVATAR;

		return {
			content: {
				username: project_path,
				icon_url: USE_ROCKETCHAT_AVATAR ? null : avatar,
				text: `The wiki page ${wiki_page_title} was ${user_action} by ${user_name}`
			}
		};
	}

	systemEvent(data) {
		const event_name = data.event_name;
		const [, eventType] = data.event_name.split('_');
		const action = eventType in ACTION_VERBS ? ACTION_VERBS[eventType] : '';
		let text = '';
		switch (event_name) {
			case 'project_create':
			case 'project_destroy':
			case 'project_update':
				text = `Project \`${data.path_with_namespace}\` ${action}.`;
				break;
			case 'project_rename':
			case 'project_transfer':
				text = `Project \`${data.old_path_with_namespace}\` ${action} to \`${data.path_with_namespace}\`.`;
				break;
			case 'user_add_to_team':
			case 'user_remove_from_team':
				text = `User \`${data.user_username}\` was ${action} to project \`${data.project_path_with_namespace}\` with \`${data.project_access}\` access.`;
				break;
			case 'user_add_to_group':
			case 'user_remove_from_group':
				text = `User \`${data.user_username}\` was ${action} to group \`${data.group_path}\` with \`${data.group_access}\` access.`;
				break;
			case 'user_create':
			case 'user_destroy':
				text = `User \`${data.username}\` was ${action}.`;
				break;
			case 'user_rename':
				text = `User \`${data.old_username}\` was ${action} to \`${data.username}\`.`;
				break;
			case 'key_create':
			case 'key_destroy':
				text = `Key \`${data.username}\` was ${action}.`;
				break;
			case 'group_create':
			case 'group_destroy':
				text = `Group \`${data.path}\` was ${action}.`;
				break;
			case 'group_rename':
				text = `Group \`${data.old_full_path}\` was ${action} to \`${data.full_path}\`.`;
				break;
			default:
				text = 'Unknown system event';
				break;
		}

		return {
			content: {
				//text: `${text}`,
				text: `${text}\n${JSON.stringify(data, null, 4)}`,
				// attachments: [
				// 	{
				// 		text: `${JSON.stringify(data, null, 4)}`,
				// 		color: NOTIF_COLOR
				// 	}
				// ]
			}
		};
	}
}

スクリプトは、githubのmalko/rocketchat-gitlab-hookから拝借してそのまま使おうと思ったのですが、attachmentsだけreturnすると、なぜかOutgoing WebHookが反応しなかったため、attachmentsの内容がtextに載るようにして、反応させました。

ソースコードは、githubにも置きました。→リンク:itc-lab/rocketchat-gitlab-hook-kai

なお、スクリプトは、JavaScriptエラーの場合、無反応になるようですが、単純に console.log を出力させるだけにしても動きませんでした。


「有効」、「スクリプトを有効にする」スイッチをオンにして、保存ボタンをクリックします。

保存後、以下のように Webhook URL が表示されるため、これをコピーしておきます。

以上で、Rocket.Chat側のGitLabからのWebHook受け入れ準備は完了です。


GitLabにOutgoing WebHookを設定


GitLabに管理者でログインし、プロジェクトの画面へ行き、「設定」→「Webhooks」をクリックします。

管理者エリア→システムフック にも似た設定がありますが、こちらは、GitLab全体に有効になります。仕様が異なりますので、「Rocket.ChatにIncoming WebHook(GitLab用)を設定」の手順で使用したScriptは正常に動作しません。

「URL」に「Rocket.ChatにIncoming WebHook(GitLab用)を設定」の手順でコピーしたURLを貼り付けます。
「Secret token」は空白で構いません。
「プッシュイベント」にチェックを入れます。
「SSL証明書検証の有効化」は、今回、Webhook URLがhttp://のため、チェックを外し、「Add webhook」をクリックします。


保存すると、以下のようにテストができるようになります。 「テスト」→「Push events」をクリックしてみます。→前回のpush内容が Rocket.Chat、Slack ともに投稿されれば成功です。


Rocket.Chat

Slack


Hook execution failed: URL 'http://[ホスト名]/hooks/aaaaaaaaaaaaaaaaa/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' is blocked: Requests to the local network are not allowed

のエラーになった場合、ローカルネットワークのWebHookを許可する設定が必要です。

この場合、以下のように設定します。


「管理者エリア」をクリックします。


「設定」→「ネットワーク」 をクリックします。


「web フックおよびサービスからのローカルネットワークへのリクエストを許可する。」にチェックを入れ、「Save changes」をクリックします。



Rocket.ChatにIncoming WebHook(Wekan用)を設定


管理者でログイン後、ユーザーのアイコンをクリックして、「管理」をクリックします。
「サービス連携」をクリックします。
「Incoming」を選択して、「+New」をクリックします。

「名前」は、"Wekan"とし、投稿先チャンネルは、"#general"とします。
「投稿ユーザー」は、Rocket.Chatで登録されているユーザー名を入力します。
「エイリアス」は、 "wekan" とします。

この場合、投稿者の名前が以下のように表示されます。


Rocket.Chat

Slack

絵文字は、アバターの画像になります。https://www.webfx.com/tools/emoji-cheat-sheet/ 等で調べて、絵文字コードを入力します。今回 :clipboard: とします。Slackへはスクリプトによって、:ghost:になります。


今回、Scriptは登録しません。スクリプトを有効にするをオフのままにします。
スクリプトを使わない理由は、以下のようにWekanから、content.text が欲しい形で送られてくるからです。content.textは、そのままチャットのテキストに採用されます。

{
  url: {
    hash: null,
    search: null,
    query: {},
    pathname: '/hooks/aaaaaaaaaaaaaaaaa/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    path: '/hooks/aaaaaaaaaaaaaaaaa/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
  },
  url_raw: '/hooks/aaaaaaaaaaaaaaaaa/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  url_params: {
    integrationId: 'aaaaaaaaaaaaaaaaa',
    token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
  },
  content: {
    text: 'foobar リスト "リスト追加" を ボード "ボード作成" に追加しました<br>' + 'http://wekan.itccorporation.jp/b/yyyyyyyyyyyyyyyyy/board',
    listId: 'bbbbbbbbbbbbbbbbb',
    boardId: 'yyyyyyyyyyyyyyyyy',
    user: 'foobar',
    description: 'act-createList'
  },
  content_raw: null,
  headers: {
    'content-type': 'application/json',
    host: '192.168.11.6:3000',
    'content-length': '265',
    connection: 'close'
  },
  body: {
    text: 'foobar リスト "リスト追加" を ボード "ボード作成" に追加しました<br>' + 'http://wekan.itccorporation.jp/b/yyyyyyyyyyyyyyyyy/board',
    listId: 'bbbbbbbbbbbbbbbbb',
    boardId: 'yyyyyyyyyyyyyyyyy',
    user: 'foobar',
    description: 'act-createList'
  },
  user: {
    _id: 'zzzzzzzzzzzzzzzzz',
    name: 'foobar',
    username: 'foobar'
  }
}

「有効」スイッチをオンにして、保存ボタンをクリックします。

保存後、以下のように Webhook URL が表示されるため、これをコピーしておきます。

以上で、Rocket.Chat側のGitLabからのWebHook受け入れ準備は完了です。


WekanにOutgoing WebHookを設定


Wekanに管理者でログインして、右上のアバターアイコンをクリック、「管理パネル」をクリックします。

「グローバルWebフック」をクリックして、
「Webフック名」は、"Rocket.Chat"として、
「URL」に「Rocket.ChatにIncoming WebHook(Wekan用)を設定」の手順でコピーしたURLを貼り付けます。
トークン(認証用オプション)は空白で構いません。
「発信Webフック」を選択して、「作成」をクリックします。

ボードを追加してみます。

Rocket.Chat

Slack


できました!


loading...