@haoling haoling / slack.sh
Created at Tue Apr 10 08:46:07 GMT 2018
slack.sh
Raw
#!/bin/bash
API_TOKEN="!!! set api token here !!!"

set -u -e

usage_exit() {
cat <<EOD 1>&2
Usage:
  eval "\$(${0} [-u bot_name] [-c channel] [-m message | -f message_filename | -j json_filename])"

Wrapper mode:
  ${0} [-u bot_name] [-c channel] -w -- command [arguments...]

Append to post:
  slack_append_to_message [-m message | -f message_filename | -q jq_command]

Update post with jq:
  slack_update_message [-q jq_command]

---- Samples ----
単純なテキストを投稿する
  eval "\$(${0} -m "test" -c "#general")"

投稿したテキストに追記する
  echo test | slack_append_to_message -f -

attachmentsの色を赤くする
  slack_update_message -q '.["attachments"][0]["color"]="#ff0000"'

実行中のファイル名、引数、日時、ホスト名を投稿する
  eval "\$((echo "\$(cd \$(dirname \$0); pwd)/\$(basename \$0) \$*"; echo \$(date "+%Y/%m/%d")" "\$(date "+%H:%M:%S"); hostname) | ${0} -f - -u "\$(hostname)" -c "#general")"
EOD
exit 1
}

if [ $# -eq 0 ]; then
  usage_exit
fi

# 変数の初期化
ATTACHMENT=1
MODE=
BOT_NAME=
CHANNEL=
MESSAGE=
JSON=

# 内部モード
last_channel() {
    jq -ncMr "${LAST_RESPONSE}"' | .["channel"]'
}
last_ts() {
    jq -ncM "${LAST_RESPONSE}"' | .["ts"]'
}
last_message() {
    jq -ncM "${LAST_RESPONSE}"' | .["message"]'
}
if [ "${1}" = "--append" ]; then
    MODE="${1}"
    LAST_RESPONSE="${2}"
    shift 2

    # 引数をパースする
    MESSAGE=
    while getopts m:f: OPT
    do
        case $OPT in
            m)  MESSAGE="$(echo -n "${OPTARG}" | jq -RscM .)"
                ;;
            f)  MESSAGE="$(cat "${OPTARG}" | jq -RscM .)"
                ;;
        esac
    done
    shift $((OPTIND - 1))
    if [ -z "${MESSAGE}" ]; then
        echo No message specified. >&2
        echo 'bash -c "exit 1"'
        exit 1
    fi
    QUERY='.["attachments"][0]["text"]+='"${MESSAGE}"

    # 更新する
    /bin/bash ${0} --update "${LAST_RESPONSE}" -q "${QUERY}"
    exit $?
elif [ "${1}" = "--update" ]; then
    MODE="${1}"
    LAST_RESPONSE="${2}"
    shift 2

    # 引数をパースする
    while getopts q: OPT
    do
        case $OPT in
            q)  JSON="$(jq -nscM "$(last_message) | ${OPTARG}")"
                ;;
        esac
    done
    shift $((OPTIND - 1))

    # 更新する
    REQUEST_JSON=$(jq -ncM --arg channel "$(last_channel)" --arg ts "$(last_ts)" "${JSON}"' | .["ts"]=$ts | .["channel"]=$channel')
    #echo -n "${REQUEST_JSON}" | jq . 1>&2; exit 1
    RESPONSE=$(echo -n "${REQUEST_JSON}" | curl -s -X POST -H 'Content-Type: application/json; charset=utf8' -H 'Authorization: Bearer '"${API_TOKEN}" --data @- 'https://slack.com/api/chat.update')
    jq -ne "${RESPONSE}"' | .ok == true' >/dev/null || (echo Failed post message to slack: "${RESPONSE}}," >&2; echo 'bash -c "exit 2"'; exit 2)
    echo 'SLACK_SH_LAST_POST_RESPONSE='"'${RESPONSE}'"
    echo 'bash -c "exit 0"'
    exit 0
elif [ "${1}" = "--reply" ]; then
    MODE="${1}"
    LAST_RESPONSE="${2}"
    shift 2

    # チャンネルとボット名をレスポンスから引っ張る
    BOT_NAME="$(jq -ncMr "${LAST_RESPONSE}"' | .["message"]["username"]')"
    CHANNEL="$(last_channel)"
fi



# 初期モード

# 引数をパースする
while getopts u:c:m:f:j:hw OPT
do
    case $OPT in
        u)  BOT_NAME=$OPTARG
            ;;
        c)  CHANNEL=$OPTARG
            ;;
        m)  MESSAGE="$(echo -n "${OPTARG}" | jq -RscM .)"
            ;;
        f)  MESSAGE="$(cat "${OPTARG}" | jq -RscM .)"
            ;;
        j)  JSON="$(cat "{$OPTARG}" | jq -scM .)"
            ;;
        h)  usage_exit
            ;;
        w)  # Wrapper mode
            set +u
            ARGS=
            while [ -n "$1" ]; do
                if [ "$1" = "-w" ]; then
                    :
                fi
                if [ "$1" = "--" ]; then
                    shift
                    break
                fi
                ARGS="${ARGS} ${1}"
                shift
            done
            COMMAND=
            while [ -n "$1" ]; do
                COMMAND="${COMMAND} "'"'"${1}"'"'
                shift
            done
            set -u
            MESSAGE=$(echo $(date "+%Y/%m/%d")" "$(date "+%H:%M:%S"); hostname; echo "${COMMAND}")
            eval "$(echo "${MESSAGE}" | /bin/bash slack.sh -f - ${ARGS})"
            slack_update_message -q '.["attachments"][0]["color"]="#fff0c1"'
            set +e
            OUT=$(eval ${COMMAND} 2>&1)
            RET=$?
            set -e
            if [ "$RET" -eq 0 ]; then
                slack_update_message -q '.["attachments"][0]["color"]="#00ff00"'
            else
                slack_update_message -q '.["attachments"][0]["color"]="#ff0000"'
            fi
            if [ -n "${OUT}" ]; then
                echo -n "${OUT}" | slack_reply -f -
            fi
            exit $RET
            ;;
    esac
done
shift $((OPTIND - 1))

if [ -z "$JSON" ]; then
    # 本文をJSONに入れる
    if [ -z "${MESSAGE}" ]; then
        echo No message specified. >&2
        echo 'bash -c "exit 1"'
        exit 1
    fi
    JSON_TEMPLATE='{"channel": "#general", "attachments":[{"text":$msg}]}';
    if [ ${ATTACHMENT} -eq 0 ]; then
        JSON_TEMPLATE='{"channel": "#general", "text":$msg}';
    fi
    JSON=$(jq -ncM --argjson msg "${MESSAGE}" "${JSON_TEMPLATE}")
fi

# ユーザー名
if [ -n "${BOT_NAME}" ]; then
    JSON=$(jq -ncM --argjson username "$(echo -n "${BOT_NAME}" | jq -RscM .)" "${JSON}"' | .["username"]=$username')
fi

# チャンネル
if [ -n "${CHANNEL}" ]; then
    JSON=$(jq -ncM --argjson channel "$(echo -n "${CHANNEL}" | jq -RscM .)" "${JSON}"' | .["channel"]=$channel')
fi

# reply
if [ "$MODE" = "--reply" ]; then
    JSON=$(jq -ncM --argjson thread_ts "$(last_ts)" "${JSON}"' | .["thread_ts"]=$thread_ts')
fi

# POSTする
#jq -n "${JSON}" 1>&2; exit 1
RESPONSE=$(jq -ncM "$JSON" | curl -s -X POST -H 'Content-Type: application/json; charset=utf-8' -H 'Authorization: Bearer '"${API_TOKEN}" --data @- 'https://slack.com/api/chat.postMessage')
jq -ne "${RESPONSE}"' | .ok == true' >/dev/null || (echo Failed post message to slack: "${RESPONSE}" >&2; echo 'bash -c "exit 2"'; exit 2)

# 更新用の設定を出力する
echo 'SLACK_SH_LAST_POST_RESPONSE='"'$(jq -ncM "${RESPONSE}")'"

# 更新用の関数を定義する
SCRIPT_PATH="$(cd $(dirname $0); pwd)/$(basename $0)"
cat <<'EOD'
slack_view_last_response() {
    jq -n "${SLACK_SH_LAST_POST_RESPONSE}"
}
EOD
cat <<EOD
slack_update_message() {
    eval "\$(/bin/bash "${SCRIPT_PATH}" --update "\${SLACK_SH_LAST_POST_RESPONSE}" \$*)"
}
slack_append_to_message() {
    eval "\$(/bin/bash "${SCRIPT_PATH}" --append "\${SLACK_SH_LAST_POST_RESPONSE}" \$*)"
}
slack_reply() {
    /bin/bash "${SCRIPT_PATH}" --reply "\${SLACK_SH_LAST_POST_RESPONSE}" \$* >/dev/null
    return $?
}
EOD
echo 'bash -c "exit 0"'
exit 0