-
Notifications
You must be signed in to change notification settings - Fork 16
/
slack.sh
141 lines (129 loc) · 4.02 KB
/
slack.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/bin/sh
# Run a command; post it and its standard input, output, and error to Slack.
#
# This program expects SLACK_WEBHOOK_URL in its environment. You can get one
# by creating a new Incoming Webhook at <https://my.slack.com/services/new>.
#
#/ Usage: slack [--attach] [--channel=<channel>] [--stdin] ...
#/ --attach post to Slack with an attachment (defaults to fixed-width text)
#/ --channel=<channel> post to this Slack channel (defaults to the integration's default channel)
#/ --stdin capture standard input and include it as a heredoc
set -e
usage() {
grep "^#/" "$0" | cut -c"4-" >&2
exit "$1"
}
ATTACH="" CHANNEL="null" STDIN=""
while [ "$#" -gt 0 ]
do
case "$1" in
-a|--attach) ATTACH="--attach" shift;;
-c|--ch|--channel) CHANNEL="\"$2\"" shift 2;;
-c*) CHANNEL="\"$(echo "$1" | cut -c"3-")\"" shift;;
--ch=*) CHANNEL="\"$(echo "$1" | cut -d"=" -f"2-")\"" shift;;
--channel=*) CHANNEL="\"$(echo "$1" | cut -d"=" -f"2-")\"" shift;;
-s|--stdin) STDIN="--stdin" shift;;
-h|--help) usage 0;;
-*) usage 1;;
*) break;;
esac
done
TMP="$(mktemp -d "/tmp/slack-XXXXXX")"
trap "rm -rf \"$TMP\"" EXIT INT QUIT TERM
# Run the command and capture standard input, output, and error.
if [ "$STDIN" ]
then
# Close standard input if it's requested and is a TTY. This offers
# some protection against accidentally piping passwords into Slack.
if [ -t 0 ]
then
echo "slack: not reading standard input from a TTY" >&2
exec <"/dev/null"
fi
tee "$TMP/stdin" | "$@" 2>&1 | tee "$TMP/stdout+stderr"
else
touch "$TMP/stdin"
"$@" 2>&1 | tee "$TMP/stdout+stderr"
fi
# Produce a properly-quoted command line for posting to Slack. This should
# be copy-pastable into a shell to run it again.
QUOTED="${SUDO_USER:-"$USER"}@$(hostname)"
if [ "$(whoami)" = "root" ]
then QUOTED="$QUOTED #"
else QUOTED="$QUOTED \$"
fi
for ARG in "$@"
do
if echo "$ARG" | grep -F -q " "
then QUOTED="$QUOTED \\\"$ARG\\\""
else QUOTED="$QUOTED $ARG"
fi
done
# Clean up quotes, newlines, tabs, and control characters for a JSON string.
jsonify() {
tr "\n\t" "\036\037" |
sed "s/$(printf "\036")/\\\\n/g; s/$(printf "\037")/\\\\t/g; s/\"/\\\\\"/g" |
tr -d "[:cntrl:]"
}
# Construct a JSON payload with attachments for each standard stream. This
# is not the default behavior because the text isn't fixed-width.
if [ "$ATTACH" ]
then
cat >"$TMP/data" <<EOF
payload={
"attachments": [
{
"fallback": "$QUOTED",
"pretext": "$QUOTED",
"mrkdwn_in": ["fallback", "pretext"],
"fields": [
EOF
cat >>"$TMP/data" <<EOF
{
"mrkdwn_in": ["text"],
"short": false,
"title": "standard input",
"value": "$(jsonify <"$TMP/stdin")"
},
EOF
cat >>"$TMP/data" <<EOF
{
"mrkdwn_in": ["text"],
"short": false,
"title": "standard output + standard error",
"value": "$(jsonify <"$TMP/stdout+stderr")"
}
]
}
],
"channel": $CHANNEL,
"username": "${SUDO_USER:-"$USER"}@$(hostname)"
}
EOF
# Construct a JSON payload the looks a bit like a shell session. This is
# the default behavior. If standard input's been captured, it is shown
# in heredoc syntax so it can be copy-pasted.
else
FENCE='```'
cat >"$TMP/data" <<EOF
payload={
"channel": $CHANNEL,
"mrkdwn": true,
"text": "$FENCE$QUOTED$(
if [ -s "$TMP/stdin" ]
then
printf " <<EOF\\\\n"
jsonify <"$TMP/stdin"
printf "EOF"
fi
)\\n$(
jsonify <"$TMP/stdout+stderr"
)$FENCE",
"username": "${SUDO_USER:-"$USER"}@$(hostname)"
}
EOF
fi
# Post to Slack and print the Slack API output to standard error.
printf "slack: " >&2
curl --data-urlencode "$(cat "$TMP/data")" -s "$SLACK_WEBHOOK_URL" >&2
echo >&2