-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·218 lines (195 loc) · 9.09 KB
/
install.sh
File metadata and controls
executable file
·218 lines (195 loc) · 9.09 KB
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/usr/bin/env bash
# ErrorWatch Python SDK — installer for FastAPI / Starlette / async-Python projects.
#
# Usage:
# curl -sSL https://raw.githubusercontent.com/MakFly/errorwatch-sdk-python/main/install.sh | bash
# curl -sSL https://raw.githubusercontent.com/MakFly/errorwatch-sdk-python/main/install.sh | bash -s -- --project /path/to/api
#
# Or locally:
# ./install.sh
# ./install.sh --project ../my-fastapi-app --api-key ew_xxx --endpoint https://errorwatch.example
#
# Flags:
# --project <dir> Target project directory (default: $PWD).
# --api-key <key> ErrorWatch project API key (skips prompt, written to .env).
# --endpoint <url> ErrorWatch instance base URL (default: https://api.errorwatch.io).
# --env <name> Environment label (default: production).
# --ref <git-ref> Git ref to install from (default: main). Use a tag for reproducibility.
# --no-env Don't touch .env / .env.example.
# --no-snippet Don't write the integration snippet file.
# --pypi Install from PyPI instead of git (when published).
# --help Show this help.
set -Eeuo pipefail
# ── defaults ─────────────────────────────────────────────────────────────────
PROJECT_DIR="${PWD}"
API_KEY=""
ENDPOINT="https://api.errorwatch.io"
ENVIRONMENT="production"
GIT_REF="main"
GIT_URL="https://github.com/MakFly/errorwatch-sdk-python.git"
PYPI_NAME="errorwatch-sdk"
USE_PYPI=0
TOUCH_ENV=1
WRITE_SNIPPET=1
# ── ui helpers ───────────────────────────────────────────────────────────────
if [[ -t 1 ]]; then
BOLD=$'\033[1m'; DIM=$'\033[2m'; RED=$'\033[31m'; GREEN=$'\033[32m'
YELLOW=$'\033[33m'; BLUE=$'\033[34m'; RESET=$'\033[0m'
else
BOLD=""; DIM=""; RED=""; GREEN=""; YELLOW=""; BLUE=""; RESET=""
fi
say() { printf "%s\n" "$*"; }
info() { printf "${BLUE}ℹ${RESET} %s\n" "$*"; }
ok() { printf "${GREEN}✓${RESET} %s\n" "$*"; }
warn() { printf "${YELLOW}!${RESET} %s\n" "$*" >&2; }
die() { printf "${RED}✗${RESET} %s\n" "$*" >&2; exit 1; }
usage() { sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'; }
# ── args ─────────────────────────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
case "$1" in
--project) PROJECT_DIR="$2"; shift 2 ;;
--api-key) API_KEY="$2"; shift 2 ;;
--endpoint) ENDPOINT="$2"; shift 2 ;;
--env) ENVIRONMENT="$2"; shift 2 ;;
--ref) GIT_REF="$2"; shift 2 ;;
--pypi) USE_PYPI=1; shift ;;
--no-env) TOUCH_ENV=0; shift ;;
--no-snippet) WRITE_SNIPPET=0; shift ;;
-h|--help) usage; exit 0 ;;
*) die "Unknown flag: $1 (use --help)" ;;
esac
done
PROJECT_DIR="$(cd "$PROJECT_DIR" 2>/dev/null && pwd || true)"
[[ -d "$PROJECT_DIR" ]] || die "Project directory not found: $PROJECT_DIR"
say ""
say "${BOLD}ErrorWatch Python SDK installer${RESET}"
say "${DIM}target: $PROJECT_DIR${RESET}"
say ""
# ── detect Python ────────────────────────────────────────────────────────────
PY=""
if [[ -x "$PROJECT_DIR/.venv/bin/python" ]]; then
PY="$PROJECT_DIR/.venv/bin/python"
info "Detected venv at .venv/"
elif [[ -x "$PROJECT_DIR/venv/bin/python" ]]; then
PY="$PROJECT_DIR/venv/bin/python"
info "Detected venv at venv/"
elif command -v python3 >/dev/null 2>&1; then
PY="$(command -v python3)"
warn "No venv found in project — using system python3 ($PY). Activate a venv first if you want isolation."
else
die "No python3 found on PATH. Install Python 3.9+ first."
fi
PY_VERSION="$("$PY" -c 'import sys;print("%d.%d"%sys.version_info[:2])')"
PY_MAJOR="${PY_VERSION%.*}"
PY_MINOR="${PY_VERSION#*.}"
if (( PY_MAJOR < 3 || (PY_MAJOR == 3 && PY_MINOR < 9) )); then
die "Python 3.9+ required, found $PY_VERSION."
fi
ok "Python $PY_VERSION ($PY)"
# ── detect FastAPI project ───────────────────────────────────────────────────
HAS_FASTAPI=0
if [[ -f "$PROJECT_DIR/requirements.txt" ]] && grep -qE '^(fastapi|starlette)([<>=!~ ]|$)' "$PROJECT_DIR/requirements.txt"; then
HAS_FASTAPI=1
fi
if [[ -f "$PROJECT_DIR/pyproject.toml" ]] && grep -qE '"(fastapi|starlette)' "$PROJECT_DIR/pyproject.toml"; then
HAS_FASTAPI=1
fi
if (( HAS_FASTAPI )); then
ok "Detected FastAPI / Starlette in dependencies"
else
warn "FastAPI not detected in this project — installing anyway (SDK also works in plain async / sync apps)."
fi
# ── install ──────────────────────────────────────────────────────────────────
if (( USE_PYPI )); then
INSTALL_SPEC="${PYPI_NAME}[fastapi]"
else
INSTALL_SPEC="errorwatch-sdk[fastapi] @ git+${GIT_URL}@${GIT_REF}"
fi
info "Installing: $INSTALL_SPEC"
"$PY" -m pip install --upgrade --quiet "pip" || true
"$PY" -m pip install --upgrade "$INSTALL_SPEC"
ok "Installed errorwatch-sdk"
# ── .env handling ────────────────────────────────────────────────────────────
if (( TOUCH_ENV )); then
ENV_FILE="$PROJECT_DIR/.env"
ENV_EXAMPLE="$PROJECT_DIR/.env.example"
add_env() {
local file="$1" key="$2" value="$3"
if [[ -f "$file" ]] && grep -qE "^${key}=" "$file"; then
return 0
fi
{
printf '\n# ErrorWatch SDK\n'
printf '%s=%s\n' "$key" "$value"
} >> "$file"
}
if [[ -n "$API_KEY" ]]; then
touch "$ENV_FILE"
add_env "$ENV_FILE" "ERRORWATCH_API_KEY" "$API_KEY"
add_env "$ENV_FILE" "ERRORWATCH_ENDPOINT" "$ENDPOINT"
add_env "$ENV_FILE" "ERRORWATCH_ENVIRONMENT" "$ENVIRONMENT"
ok "Wrote credentials to .env"
else
touch "$ENV_EXAMPLE"
add_env "$ENV_EXAMPLE" "ERRORWATCH_API_KEY" ""
add_env "$ENV_EXAMPLE" "ERRORWATCH_ENDPOINT" "$ENDPOINT"
add_env "$ENV_EXAMPLE" "ERRORWATCH_ENVIRONMENT" "$ENVIRONMENT"
ok "Added ERRORWATCH_* keys to .env.example (no API key provided — pass --api-key or edit .env yourself)"
fi
fi
# ── snippet ──────────────────────────────────────────────────────────────────
if (( WRITE_SNIPPET )); then
SNIPPET_DIR="$PROJECT_DIR"
[[ -d "$PROJECT_DIR/app" ]] && SNIPPET_DIR="$PROJECT_DIR/app"
SNIPPET="$SNIPPET_DIR/errorwatch_setup.py"
if [[ -f "$SNIPPET" ]]; then
warn "$(basename "$SNIPPET") already exists — leaving it alone."
else
cat > "$SNIPPET" <<'PY'
"""ErrorWatch SDK bootstrap. Call ``setup_errorwatch(app)`` from your FastAPI
entrypoint right after creating the FastAPI() instance.
"""
from __future__ import annotations
import os
import errorwatch
from errorwatch.integrations.fastapi import install, lifespan_shutdown_hook
def setup_errorwatch(app) -> None:
"""Initialise the ErrorWatch client and wire it into the FastAPI app.
Reads the following env vars (all optional except API key):
- ERRORWATCH_API_KEY (required — SDK stays inert if absent)
- ERRORWATCH_ENDPOINT (default: https://api.errorwatch.io)
- ERRORWATCH_ENVIRONMENT (default: production)
- ERRORWATCH_RELEASE (e.g. git SHA / semver)
- ERRORWATCH_PROJECT_ROOT (used for in_app frame detection)
"""
errorwatch.init(
api_key=os.getenv("ERRORWATCH_API_KEY", ""),
endpoint=os.getenv("ERRORWATCH_ENDPOINT", "https://api.errorwatch.io"),
environment=os.getenv("ERRORWATCH_ENVIRONMENT", "production"),
release=os.getenv("ERRORWATCH_RELEASE"),
project_root=os.getenv("ERRORWATCH_PROJECT_ROOT"),
)
install(app)
lifespan_shutdown_hook(app)
PY
ok "Wrote integration snippet: ${SNIPPET#$PROJECT_DIR/}"
fi
fi
# ── done ─────────────────────────────────────────────────────────────────────
say ""
say "${BOLD}Next steps${RESET}"
say " 1. Edit your FastAPI entrypoint (e.g. ${BOLD}app/main.py${RESET}) and add:"
say ""
say " ${DIM}from app.errorwatch_setup import setup_errorwatch${RESET}"
say " ${DIM}app = FastAPI(...)${RESET}"
say " ${DIM}setup_errorwatch(app)${RESET}"
say ""
if [[ -z "$API_KEY" ]] && (( TOUCH_ENV )); then
say " 2. Set ${BOLD}ERRORWATCH_API_KEY${RESET} in your .env (see .env.example)."
else
say " 2. ${BOLD}ERRORWATCH_API_KEY${RESET} is already set in .env."
fi
say " 3. Restart your app. Unhandled exceptions are reported to ${BOLD}$ENDPOINT${RESET}."
say ""
say "${DIM}Docs: https://github.com/MakFly/errorwatch-sdk-python${RESET}"
say "${GREEN}Installed.${RESET}"