- 記事一覧 >
- ブログ記事
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_request
のreturn
のところの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
できました!
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。