mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-28 17:22:01 +08:00
feat: Offer to send an anonymous failure report in the install script (#37016)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+55
-3
@@ -12,7 +12,7 @@
|
||||
# Source: https://github.com/n8n-io/n8n/blob/master/docker/get-n8n.sh
|
||||
set -eu
|
||||
|
||||
SCRIPT_VERSION="1.2.0"
|
||||
SCRIPT_VERSION="1.3.0"
|
||||
# The version to install is derived from the latest stable GitHub release in
|
||||
# resolve_n8n_version(); this fallback only applies when that lookup fails.
|
||||
FALLBACK_N8N_VERSION="2.32.0"
|
||||
@@ -31,6 +31,19 @@ UPGRADE=0
|
||||
NO_START=0
|
||||
REQUESTED_VERSION=""
|
||||
|
||||
# Anonymous failure report (RudderStack): offered only when an install or
|
||||
# upgrade fails, and sent only after the user answers yes. The payload is the
|
||||
# script version, OS name, install|upgrade mode and the failed step — nothing
|
||||
# else. The write key is a public client-side key. DO_NOT_TRACK=1 disables
|
||||
# the offer entirely.
|
||||
TELEMETRY_URL="https://nnrry.dataplane.rudderstack.com/v1/track"
|
||||
TELEMETRY_WRITE_KEY="3IDNZwfcE0lfjVDb0Y1wp8ZVGlg"
|
||||
# Set before steps whose failure could be on n8n's side (stack definition
|
||||
# download, image pulls, container start, health check). Failures of the
|
||||
# user's environment (no docker, port taken, ...) leave it empty and no
|
||||
# report is offered.
|
||||
STEP=""
|
||||
|
||||
# Apply ANSI styling only when stdout is a terminal that supports it and the
|
||||
# user hasn't opted out (https://no-color.org).
|
||||
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != "dumb" ]; then
|
||||
@@ -53,8 +66,36 @@ fi
|
||||
|
||||
say() { printf '%s\n' "$*"; }
|
||||
ok() { printf '%s\342\234\224%s %s\n' "$GREEN" "$RESET" "$*"; }
|
||||
|
||||
# Never sends without an explicit yes. The prompt uses /dev/tty because
|
||||
# 'curl | sh' owns stdin; without a terminal there is no prompt and no report.
|
||||
offer_failure_report() {
|
||||
[ -n "$STEP" ] || return 0
|
||||
[ -z "${DO_NOT_TRACK:-}" ] || return 0
|
||||
printf '\nSend an anonymous failure report to n8n, so we can fix this?\n(script version, OS name, failed step — nothing else) [y/N] ' >/dev/tty 2>/dev/null || return 0
|
||||
read -r answer </dev/tty 2>/dev/null || return 0
|
||||
case "$answer" in
|
||||
[Yy]*) ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
mode="install"
|
||||
[ "$UPGRADE" -eq 1 ] && mode="upgrade"
|
||||
body="{\"anonymousId\":\"$(gen_secret)\",\"event\":\"install_failed\",\"properties\":{\"scriptVersion\":\"${SCRIPT_VERSION}\",\"os\":\"$(uname -s)\",\"mode\":\"${mode}\",\"step\":\"${STEP}\"}}"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -s -o /dev/null --max-time 5 -u "${TELEMETRY_WRITE_KEY}:" \
|
||||
-H 'Content-Type: application/json' -d "$body" "$TELEMETRY_URL" 2>/dev/null || true
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q -O /dev/null -T 5 \
|
||||
--header="Authorization: Basic $(printf '%s:' "$TELEMETRY_WRITE_KEY" | base64)" \
|
||||
--header='Content-Type: application/json' \
|
||||
--post-data="$body" "$TELEMETRY_URL" 2>/dev/null || true
|
||||
fi
|
||||
printf 'Thank you!\n' >/dev/tty 2>/dev/null || true
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '%sError:%s %s\n' "$RED" "$RED_RESET" "$*" >&2
|
||||
offer_failure_report
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -77,6 +118,7 @@ Options:
|
||||
|
||||
Environment:
|
||||
N8N_DIR Install directory (default: ./n8n)
|
||||
DO_NOT_TRACK=1 Never offer to send an anonymous failure report.
|
||||
|
||||
For production-grade setups (TLS, Postgres, queue mode) see:
|
||||
${DOCS_HOSTING_URL}
|
||||
@@ -312,6 +354,7 @@ compose() {
|
||||
check_rate_limit() {
|
||||
grep -qiE 'toomanyrequests|rate ?limit' "$1" || return 0
|
||||
rm -f "$1"
|
||||
STEP="docker-hub-rate-limit"
|
||||
fail "Docker Hub pull rate limit reached — your configuration in ${N8N_DIR} is
|
||||
unaffected. Wait about an hour, then start n8n with:
|
||||
docker compose -f ${N8N_DIR}/compose.yml up -d
|
||||
@@ -374,7 +417,9 @@ do_upgrade() {
|
||||
fi
|
||||
|
||||
say "Pulling images..."
|
||||
STEP="image-pull"
|
||||
compose_pull
|
||||
STEP="container-start"
|
||||
compose_checked up -d --quiet-pull
|
||||
ok "Restarted with n8n ${target}"
|
||||
}
|
||||
@@ -425,6 +470,7 @@ main() {
|
||||
if [ -f "${N8N_DIR}/compose.yml" ] || [ -f "${N8N_DIR}/.env" ]; then
|
||||
if [ "$UPGRADE" -eq 1 ]; then
|
||||
do_upgrade
|
||||
STEP="n8n-readiness-timeout"
|
||||
wait_for_n8n || fail "n8n did not become ready — check 'docker compose -f ${N8N_DIR}/compose.yml logs n8n'."
|
||||
print_summary
|
||||
exit 0
|
||||
@@ -434,10 +480,11 @@ main() {
|
||||
if http_get "http://127.0.0.1:${N8N_PORT}/healthz"; then
|
||||
say "n8n is already running at: http://localhost:${N8N_PORT}"
|
||||
else
|
||||
say "To start it: docker compose -f ${N8N_DIR}/compose.yml up -d"
|
||||
say "To start it: docker compose -f ${N8N_DIR}/compose.yml up -d"
|
||||
say "Once started, n8n runs at: http://localhost:${N8N_PORT}"
|
||||
fi
|
||||
say "To upgrade: curl -fsSL https://get.n8n.io | sh -s -- --upgrade"
|
||||
say "To upgrade: curl -fsSL https://get.n8n.io | sh -s -- --upgrade"
|
||||
say "To uninstall: docker compose -f ${N8N_DIR}/compose.yml down -v && rm -rf ${N8N_DIR} # DELETES all n8n data"
|
||||
check_compose_freshness
|
||||
exit 0
|
||||
fi
|
||||
@@ -454,7 +501,9 @@ main() {
|
||||
|
||||
INSTALL_VERSION="${REQUESTED_VERSION:-$(resolve_n8n_version)}"
|
||||
mkdir -p "${N8N_DIR}"
|
||||
STEP="stack-definition-download"
|
||||
write_compose
|
||||
STEP=""
|
||||
ok "Created ${N8N_DIR}/compose.yml"
|
||||
write_searxng_settings
|
||||
ok "Created ${N8N_DIR}/searxng-settings.yml"
|
||||
@@ -469,9 +518,12 @@ main() {
|
||||
fi
|
||||
|
||||
say "Pulling images (this can take a few minutes on first run)..."
|
||||
STEP="image-pull"
|
||||
compose_pull
|
||||
STEP="container-start"
|
||||
compose_checked up -d --quiet-pull
|
||||
ok "Started n8n ${INSTALL_VERSION} and sandbox services"
|
||||
STEP="n8n-readiness-timeout"
|
||||
wait_for_n8n || fail "n8n did not become ready — check 'docker compose -f ${N8N_DIR}/compose.yml logs n8n'."
|
||||
print_summary
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ SCRIPT="$(cd "$(dirname "$0")" && pwd)/get-n8n.sh"
|
||||
# on master — the harness must test this branch's compose file.
|
||||
COMPOSE_SRC="$(cd "$(dirname "$0")" && pwd)/get-n8n-compose.yml"
|
||||
export N8N_COMPOSE_URL="$COMPOSE_SRC"
|
||||
# Failure-path tests must not prompt for (or send) a failure report.
|
||||
export DO_NOT_TRACK=1
|
||||
E2E=0
|
||||
[ "${1:-}" = "--e2e" ] && E2E=1
|
||||
|
||||
@@ -61,6 +63,8 @@ sh "$SCRIPT" --version | grep -q '^get-n8n.sh v' && pass "--version prints scrip
|
||||
fail "--version prints script version"
|
||||
sh "$SCRIPT" --help | grep -q 'Usage:' && pass "--help prints usage" ||
|
||||
fail "--help prints usage"
|
||||
sh "$SCRIPT" --help | grep -q 'DO_NOT_TRACK' && pass "--help documents DO_NOT_TRACK" ||
|
||||
fail "--help documents DO_NOT_TRACK"
|
||||
check_not "unknown flag fails" sh "$SCRIPT" --bogus
|
||||
|
||||
# fresh --no-start install
|
||||
@@ -103,6 +107,8 @@ rerun_out="$(env N8N_DIR="$WORK/a" sh "$SCRIPT" 2>&1)" && pass "re-run on existi
|
||||
fail "re-run leaves files untouched"
|
||||
echo "$rerun_out" | grep -q 'http://localhost:5678' && pass "re-run tells the user where n8n runs" ||
|
||||
fail "re-run tells the user where n8n runs"
|
||||
echo "$rerun_out" | grep -q 'To uninstall: docker compose' && pass "re-run shows the uninstall command" ||
|
||||
fail "re-run shows the uninstall command"
|
||||
|
||||
# stack definition versioning
|
||||
[ -n "$(sed -n 's/^# compose-version: *//p' "$WORK/a/compose.yml")" ] &&
|
||||
@@ -171,6 +177,52 @@ ratelimit_out="$(env PATH="$WORK/shim:$PATH" N8N_DIR="$WORK/ratelimit" sh "$SCRI
|
||||
echo "$ratelimit_out" | grep -q 'pull rate limit reached' && pass "rate-limit failure prints recovery advice" ||
|
||||
fail "rate-limit failure prints recovery advice"
|
||||
|
||||
# failure-report consent: a reportable failure on a terminal must prompt, send
|
||||
# the failed step only on an explicit yes, and send nothing on the default No.
|
||||
# Needs a pty, so run the script under script(1); its syntax differs between
|
||||
# util-linux and BSD/macOS, and Git Bash has neither. The curl shim records
|
||||
# telemetry calls and fails everything else the way an offline curl would.
|
||||
if [ "$WINDOWS" -eq 0 ] && command -v script >/dev/null 2>&1; then
|
||||
cat >"$WORK/shim/curl" <<EOF
|
||||
#!/bin/sh
|
||||
case "\$*" in
|
||||
*rudderstack*) echo "\$*" >>"$WORK/consent.log" ;;
|
||||
esac
|
||||
exit 6
|
||||
EOF
|
||||
chmod +x "$WORK/shim/curl"
|
||||
run_with_tty() { # run_with_tty <answer> <cmd...>
|
||||
answer="$1"
|
||||
shift
|
||||
if script --version 2>/dev/null | grep -q util-linux; then
|
||||
{
|
||||
sleep 1
|
||||
printf '%s\n' "$answer"
|
||||
sleep 4
|
||||
} | script -qec "$*" /dev/null
|
||||
else
|
||||
{
|
||||
sleep 1
|
||||
printf '%s\n' "$answer"
|
||||
sleep 4
|
||||
} | script -q /dev/null "$@"
|
||||
fi
|
||||
}
|
||||
rm -f "$WORK/consent.log"
|
||||
run_with_tty y env "PATH=$WORK/shim:$PATH" DO_NOT_TRACK= N8N_DIR="$WORK/ratelimit" \
|
||||
sh "$SCRIPT" --upgrade --version 2.32.0 >/dev/null 2>&1
|
||||
grep -q '"event":"install_failed".*"step":"docker-hub-rate-limit"' "$WORK/consent.log" 2>/dev/null &&
|
||||
pass "consented failure report carries the failed step" ||
|
||||
fail "consented failure report carries the failed step"
|
||||
rm -f "$WORK/consent.log"
|
||||
run_with_tty '' env "PATH=$WORK/shim:$PATH" DO_NOT_TRACK= N8N_DIR="$WORK/ratelimit" \
|
||||
sh "$SCRIPT" --upgrade --version 2.32.0 >/dev/null 2>&1
|
||||
[ ! -s "$WORK/consent.log" ] && pass "declined failure report sends nothing" ||
|
||||
fail "declined failure report sends nothing"
|
||||
else
|
||||
skip "failure-report consent tests (need script(1) for a pty)"
|
||||
fi
|
||||
|
||||
# truncated download must execute nothing
|
||||
mkdir -p "$WORK/trunc" && cd "$WORK/trunc" || exit 1
|
||||
head -c 1000 "$SCRIPT" | sh >/dev/null 2>&1
|
||||
|
||||
Reference in New Issue
Block a user