claude-agent-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/bin/claude-framework +3 -0
- package/framework/agents/design-lead.md +240 -0
- package/framework/agents/product-owner.md +179 -0
- package/framework/agents/tech-lead.md +226 -0
- package/framework/commands/ayuda.md +127 -0
- package/framework/commands/a/303/261adir.md +98 -0
- package/framework/commands/backup.md +397 -0
- package/framework/commands/cambiar.md +110 -0
- package/framework/commands/cloud.md +457 -0
- package/framework/commands/code.md +142 -0
- package/framework/commands/debug.md +334 -0
- package/framework/commands/deploy.md +383 -0
- package/framework/commands/deshacer.md +120 -0
- package/framework/commands/estado.md +218 -0
- package/framework/commands/explica.md +227 -0
- package/framework/commands/feature.md +120 -0
- package/framework/commands/git.md +427 -0
- package/framework/commands/historial.md +202 -0
- package/framework/commands/learn.md +408 -0
- package/framework/commands/movil.md +245 -0
- package/framework/commands/nuevo.md +118 -0
- package/framework/commands/plan.md +134 -0
- package/framework/commands/prd.md +113 -0
- package/framework/commands/probar.md +148 -0
- package/framework/commands/revisar.md +208 -0
- package/framework/commands/seeds.md +230 -0
- package/framework/commands/seguridad.md +226 -0
- package/framework/commands/tasks.md +157 -0
- package/framework/skills/architecture/algorithms.md +970 -0
- package/framework/skills/architecture/clean-code.md +1080 -0
- package/framework/skills/architecture/design-patterns.md +1984 -0
- package/framework/skills/architecture/functional-programming.md +972 -0
- package/framework/skills/architecture/solid.md +991 -0
- package/framework/skills/cloud/cloud-aws.md +848 -0
- package/framework/skills/cloud/cloud-azure.md +931 -0
- package/framework/skills/cloud/cloud-gcp.md +848 -0
- package/framework/skills/cloud/message-queues.md +1229 -0
- package/framework/skills/core/accessibility.md +401 -0
- package/framework/skills/core/api.md +474 -0
- package/framework/skills/core/authentication.md +306 -0
- package/framework/skills/core/authorization.md +388 -0
- package/framework/skills/core/background-jobs.md +341 -0
- package/framework/skills/core/caching.md +473 -0
- package/framework/skills/core/code-review.md +341 -0
- package/framework/skills/core/controllers.md +290 -0
- package/framework/skills/core/cua.md +285 -0
- package/framework/skills/core/documentation.md +472 -0
- package/framework/skills/core/file-uploads.md +351 -0
- package/framework/skills/core/hotwire-native.md +296 -0
- package/framework/skills/core/hotwire.md +278 -0
- package/framework/skills/core/i18n.md +334 -0
- package/framework/skills/core/imports-exports.md +750 -0
- package/framework/skills/core/infrastructure.md +337 -0
- package/framework/skills/core/models.md +228 -0
- package/framework/skills/core/notifications.md +672 -0
- package/framework/skills/core/payments.md +581 -0
- package/framework/skills/core/performance.md +361 -0
- package/framework/skills/core/rails-scaffold.md +131 -0
- package/framework/skills/core/search.md +518 -0
- package/framework/skills/core/security.md +565 -0
- package/framework/skills/core/seeds.md +307 -0
- package/framework/skills/core/seo.md +542 -0
- package/framework/skills/core/testing.md +393 -0
- package/framework/skills/core/views.md +260 -0
- package/framework/skills/core/websockets.md +564 -0
- package/framework/skills/data/advanced-sql.md +1204 -0
- package/framework/skills/data/nosql.md +1141 -0
- package/framework/skills/devops/containers-advanced.md +1237 -0
- package/framework/skills/devops/debugging.md +834 -0
- package/framework/skills/devops/git-workflow.md +752 -0
- package/framework/skills/devops/networking.md +932 -0
- package/framework/skills/devops/shell-scripting.md +1132 -0
- package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
- package/framework/sub-agents/cloud-agent.md +677 -0
- package/framework/sub-agents/data.md +504 -0
- package/framework/sub-agents/debugging-agent.md +554 -0
- package/framework/sub-agents/devops.md +483 -0
- package/framework/sub-agents/docs.md +176 -0
- package/framework/sub-agents/frontend-dev.md +349 -0
- package/framework/sub-agents/git-workflow-agent.md +697 -0
- package/framework/sub-agents/integrations.md +630 -0
- package/framework/sub-agents/native-dev.md +434 -0
- package/framework/sub-agents/qa.md +138 -0
- package/framework/sub-agents/rails-dev.md +375 -0
- package/framework/sub-agents/security.md +526 -0
- package/framework/sub-agents/ui.md +437 -0
- package/framework/sub-agents/ux.md +284 -0
- package/framework/templates/api-spec.md +500 -0
- package/framework/templates/component-spec.md +248 -0
- package/framework/templates/feature.json +13 -0
- package/framework/templates/model-spec.md +318 -0
- package/framework/templates/prd-template.md +80 -0
- package/framework/templates/task-plan.md +122 -0
- package/framework/templates/task-user-story.md +52 -0
- package/framework/templates/technical-spec.md +260 -0
- package/framework/templates/user-story.md +95 -0
- package/package.json +42 -0
- package/project-templates/CLAUDE.md +42 -0
- package/project-templates/contexts/architecture.md +25 -0
- package/project-templates/contexts/conventions.md +46 -0
- package/project-templates/contexts/design-system.md +47 -0
- package/project-templates/contexts/requirements.md +38 -0
- package/project-templates/contexts/stack.md +30 -0
- package/project-templates/history/active/models.md +11 -0
- package/project-templates/history/changelog.md +15 -0
- package/project-templates/workspace/.gitkeep +0 -0
- package/src/cli.js +52 -0
- package/src/init.js +104 -0
- package/src/status.js +75 -0
- package/src/update.js +88 -0
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
# Skill: Shell Scripting
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Automatizar tareas repetitivas y operaciones de DevOps usando Bash scripting para proyectos Rails.
|
|
6
|
+
|
|
7
|
+
## Basics
|
|
8
|
+
|
|
9
|
+
### Variables
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
#!/bin/bash
|
|
13
|
+
|
|
14
|
+
# Asignación (sin espacios alrededor de =)
|
|
15
|
+
NAME="myapp"
|
|
16
|
+
VERSION="1.0.0"
|
|
17
|
+
COUNT=42
|
|
18
|
+
|
|
19
|
+
# Uso de variables
|
|
20
|
+
echo "Deploying $NAME version $VERSION"
|
|
21
|
+
echo "Deploying ${NAME} version ${VERSION}" # Más explícito
|
|
22
|
+
|
|
23
|
+
# Variables de solo lectura
|
|
24
|
+
readonly DB_NAME="production"
|
|
25
|
+
|
|
26
|
+
# Variables por defecto
|
|
27
|
+
RAILS_ENV="${RAILS_ENV:-development}" # development si no está definida
|
|
28
|
+
PORT="${PORT:=3000}" # Asigna 3000 si no está definida
|
|
29
|
+
|
|
30
|
+
# Resultado de comando
|
|
31
|
+
CURRENT_DATE=$(date +%Y-%m-%d)
|
|
32
|
+
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
33
|
+
|
|
34
|
+
# Aritmética
|
|
35
|
+
COUNT=$((COUNT + 1))
|
|
36
|
+
TOTAL=$((10 * 5))
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Arrays
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
#!/bin/bash
|
|
43
|
+
|
|
44
|
+
# Declarar array
|
|
45
|
+
SERVERS=("web1" "web2" "web3")
|
|
46
|
+
TASKS=("migrate" "assets" "restart")
|
|
47
|
+
|
|
48
|
+
# Acceder a elementos
|
|
49
|
+
echo "${SERVERS[0]}" # web1
|
|
50
|
+
echo "${SERVERS[@]}" # Todos los elementos
|
|
51
|
+
echo "${#SERVERS[@]}" # Número de elementos (3)
|
|
52
|
+
echo "${SERVERS[@]:1:2}" # Slice: web2 web3
|
|
53
|
+
|
|
54
|
+
# Añadir elementos
|
|
55
|
+
SERVERS+=("web4")
|
|
56
|
+
|
|
57
|
+
# Iterar
|
|
58
|
+
for server in "${SERVERS[@]}"; do
|
|
59
|
+
echo "Deploying to $server"
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
# Array asociativo (Bash 4+)
|
|
63
|
+
declare -A CONFIG
|
|
64
|
+
CONFIG[host]="localhost"
|
|
65
|
+
CONFIG[port]="5432"
|
|
66
|
+
CONFIG[database]="myapp_production"
|
|
67
|
+
|
|
68
|
+
echo "Connecting to ${CONFIG[host]}:${CONFIG[port]}"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Strings
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
#!/bin/bash
|
|
75
|
+
|
|
76
|
+
STR="Hello World"
|
|
77
|
+
|
|
78
|
+
# Longitud
|
|
79
|
+
echo "${#STR}" # 11
|
|
80
|
+
|
|
81
|
+
# Substring
|
|
82
|
+
echo "${STR:0:5}" # Hello
|
|
83
|
+
echo "${STR:6}" # World
|
|
84
|
+
|
|
85
|
+
# Reemplazo
|
|
86
|
+
echo "${STR/World/Rails}" # Hello Rails
|
|
87
|
+
echo "${STR//o/0}" # Hell0 W0rld (todos)
|
|
88
|
+
|
|
89
|
+
# Eliminar patrón
|
|
90
|
+
FILE="app/models/user.rb"
|
|
91
|
+
echo "${FILE%.rb}" # app/models/user (elimina suffix)
|
|
92
|
+
echo "${FILE##*/}" # user.rb (elimina prefix hasta /)
|
|
93
|
+
echo "${FILE%/*}" # app/models (directorio)
|
|
94
|
+
|
|
95
|
+
# Mayúsculas/minúsculas (Bash 4+)
|
|
96
|
+
echo "${STR,,}" # hello world
|
|
97
|
+
echo "${STR^^}" # HELLO WORLD
|
|
98
|
+
|
|
99
|
+
# Verificar si está vacío
|
|
100
|
+
if [[ -z "$VAR" ]]; then
|
|
101
|
+
echo "VAR está vacía"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
if [[ -n "$VAR" ]]; then
|
|
105
|
+
echo "VAR tiene valor"
|
|
106
|
+
fi
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Control Flow
|
|
110
|
+
|
|
111
|
+
### If/Else
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
#!/bin/bash
|
|
115
|
+
|
|
116
|
+
# Básico
|
|
117
|
+
if [[ $RAILS_ENV == "production" ]]; then
|
|
118
|
+
echo "Production mode"
|
|
119
|
+
elif [[ $RAILS_ENV == "staging" ]]; then
|
|
120
|
+
echo "Staging mode"
|
|
121
|
+
else
|
|
122
|
+
echo "Development mode"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Operadores de comparación (strings)
|
|
126
|
+
[[ $a == $b ]] # Igual
|
|
127
|
+
[[ $a != $b ]] # Diferente
|
|
128
|
+
[[ $a < $b ]] # Menor (alfabético)
|
|
129
|
+
[[ $a =~ ^[0-9]+$ ]] # Regex match
|
|
130
|
+
|
|
131
|
+
# Operadores de comparación (números)
|
|
132
|
+
[[ $a -eq $b ]] # Igual
|
|
133
|
+
[[ $a -ne $b ]] # Diferente
|
|
134
|
+
[[ $a -lt $b ]] # Menor que
|
|
135
|
+
[[ $a -le $b ]] # Menor o igual
|
|
136
|
+
[[ $a -gt $b ]] # Mayor que
|
|
137
|
+
[[ $a -ge $b ]] # Mayor o igual
|
|
138
|
+
|
|
139
|
+
# Operadores lógicos
|
|
140
|
+
[[ $a && $b ]] # AND
|
|
141
|
+
[[ $a || $b ]] # OR
|
|
142
|
+
[[ ! $a ]] # NOT
|
|
143
|
+
|
|
144
|
+
# Verificar archivos
|
|
145
|
+
[[ -f "$FILE" ]] # Archivo existe
|
|
146
|
+
[[ -d "$DIR" ]] # Directorio existe
|
|
147
|
+
[[ -r "$FILE" ]] # Legible
|
|
148
|
+
[[ -w "$FILE" ]] # Escribible
|
|
149
|
+
[[ -x "$FILE" ]] # Ejecutable
|
|
150
|
+
[[ -s "$FILE" ]] # Tamaño > 0
|
|
151
|
+
|
|
152
|
+
# One-liner
|
|
153
|
+
[[ -f config.yml ]] && echo "Config exists" || echo "Config missing"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Case
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
#!/bin/bash
|
|
160
|
+
|
|
161
|
+
case "$COMMAND" in
|
|
162
|
+
start)
|
|
163
|
+
echo "Starting server..."
|
|
164
|
+
rails server -d
|
|
165
|
+
;;
|
|
166
|
+
stop)
|
|
167
|
+
echo "Stopping server..."
|
|
168
|
+
pkill -f "rails server"
|
|
169
|
+
;;
|
|
170
|
+
restart)
|
|
171
|
+
$0 stop
|
|
172
|
+
$0 start
|
|
173
|
+
;;
|
|
174
|
+
status)
|
|
175
|
+
pgrep -f "rails server" && echo "Running" || echo "Stopped"
|
|
176
|
+
;;
|
|
177
|
+
*)
|
|
178
|
+
echo "Usage: $0 {start|stop|restart|status}"
|
|
179
|
+
exit 1
|
|
180
|
+
;;
|
|
181
|
+
esac
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### For Loop
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
#!/bin/bash
|
|
188
|
+
|
|
189
|
+
# Lista simple
|
|
190
|
+
for env in development staging production; do
|
|
191
|
+
echo "Environment: $env"
|
|
192
|
+
done
|
|
193
|
+
|
|
194
|
+
# Rango
|
|
195
|
+
for i in {1..5}; do
|
|
196
|
+
echo "Iteration $i"
|
|
197
|
+
done
|
|
198
|
+
|
|
199
|
+
# Rango con paso
|
|
200
|
+
for i in {0..10..2}; do
|
|
201
|
+
echo "Even: $i"
|
|
202
|
+
done
|
|
203
|
+
|
|
204
|
+
# Estilo C
|
|
205
|
+
for ((i=0; i<10; i++)); do
|
|
206
|
+
echo "Index: $i"
|
|
207
|
+
done
|
|
208
|
+
|
|
209
|
+
# Archivos
|
|
210
|
+
for file in app/models/*.rb; do
|
|
211
|
+
echo "Processing $file"
|
|
212
|
+
done
|
|
213
|
+
|
|
214
|
+
# Líneas de archivo
|
|
215
|
+
while IFS= read -r line; do
|
|
216
|
+
echo "Line: $line"
|
|
217
|
+
done < config/servers.txt
|
|
218
|
+
|
|
219
|
+
# Resultado de comando
|
|
220
|
+
for user in $(cat /etc/passwd | cut -d: -f1); do
|
|
221
|
+
echo "User: $user"
|
|
222
|
+
done
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### While Loop
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
#!/bin/bash
|
|
229
|
+
|
|
230
|
+
# Contador
|
|
231
|
+
count=0
|
|
232
|
+
while [[ $count -lt 5 ]]; do
|
|
233
|
+
echo "Count: $count"
|
|
234
|
+
((count++))
|
|
235
|
+
done
|
|
236
|
+
|
|
237
|
+
# Esperar condición
|
|
238
|
+
while ! pg_isready -h localhost -p 5432; do
|
|
239
|
+
echo "Waiting for PostgreSQL..."
|
|
240
|
+
sleep 2
|
|
241
|
+
done
|
|
242
|
+
echo "PostgreSQL is ready!"
|
|
243
|
+
|
|
244
|
+
# Loop infinito con break
|
|
245
|
+
while true; do
|
|
246
|
+
read -p "Enter command (quit to exit): " cmd
|
|
247
|
+
[[ $cmd == "quit" ]] && break
|
|
248
|
+
eval "$cmd"
|
|
249
|
+
done
|
|
250
|
+
|
|
251
|
+
# Until (opuesto a while)
|
|
252
|
+
until [[ -f /tmp/ready.flag ]]; do
|
|
253
|
+
echo "Waiting for ready flag..."
|
|
254
|
+
sleep 1
|
|
255
|
+
done
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Funciones
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
#!/bin/bash
|
|
262
|
+
|
|
263
|
+
# Función simple
|
|
264
|
+
greet() {
|
|
265
|
+
echo "Hello, World!"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# Función con argumentos
|
|
269
|
+
deploy() {
|
|
270
|
+
local server=$1
|
|
271
|
+
local branch=${2:-main} # Default: main
|
|
272
|
+
|
|
273
|
+
echo "Deploying $branch to $server"
|
|
274
|
+
ssh "$server" "cd /app && git pull origin $branch && bundle install"
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
# Uso
|
|
278
|
+
deploy "web1.example.com" "feature/new-design"
|
|
279
|
+
deploy "web2.example.com" # Usa branch main
|
|
280
|
+
|
|
281
|
+
# Retornar valor (0-255)
|
|
282
|
+
is_production() {
|
|
283
|
+
[[ $RAILS_ENV == "production" ]]
|
|
284
|
+
return $? # 0 si true, 1 si false
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if is_production; then
|
|
288
|
+
echo "Production checks enabled"
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# Retornar string
|
|
292
|
+
get_version() {
|
|
293
|
+
cat VERSION
|
|
294
|
+
}
|
|
295
|
+
VERSION=$(get_version)
|
|
296
|
+
|
|
297
|
+
# Variables locales
|
|
298
|
+
calculate() {
|
|
299
|
+
local result=$(($1 + $2))
|
|
300
|
+
echo $result
|
|
301
|
+
}
|
|
302
|
+
SUM=$(calculate 5 3) # 8
|
|
303
|
+
|
|
304
|
+
# Función con validación
|
|
305
|
+
backup_database() {
|
|
306
|
+
local db_name=$1
|
|
307
|
+
local backup_path=$2
|
|
308
|
+
|
|
309
|
+
if [[ -z "$db_name" ]] || [[ -z "$backup_path" ]]; then
|
|
310
|
+
echo "Usage: backup_database <db_name> <backup_path>" >&2
|
|
311
|
+
return 1
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
pg_dump "$db_name" > "$backup_path"
|
|
315
|
+
return $?
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Pipes y Redirección
|
|
320
|
+
|
|
321
|
+
### Pipes
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
#!/bin/bash
|
|
325
|
+
|
|
326
|
+
# Encadenar comandos
|
|
327
|
+
cat access.log | grep "POST" | wc -l
|
|
328
|
+
|
|
329
|
+
# Múltiples pipes
|
|
330
|
+
ps aux | grep rails | grep -v grep | awk '{print $2}'
|
|
331
|
+
|
|
332
|
+
# Pipe a while
|
|
333
|
+
cat servers.txt | while read server; do
|
|
334
|
+
echo "Checking $server"
|
|
335
|
+
ping -c 1 "$server"
|
|
336
|
+
done
|
|
337
|
+
|
|
338
|
+
# tee: escribir a archivo y stdout
|
|
339
|
+
bundle install 2>&1 | tee install.log
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Redirección
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
#!/bin/bash
|
|
346
|
+
|
|
347
|
+
# Redireccionar stdout
|
|
348
|
+
echo "Log message" > app.log # Sobrescribir
|
|
349
|
+
echo "Another line" >> app.log # Añadir
|
|
350
|
+
|
|
351
|
+
# Redireccionar stderr
|
|
352
|
+
command 2> error.log # Solo stderr
|
|
353
|
+
command 2>> error.log # Añadir stderr
|
|
354
|
+
|
|
355
|
+
# Ambos a mismo archivo
|
|
356
|
+
command > output.log 2>&1 # stdout y stderr
|
|
357
|
+
command &> output.log # Forma corta (Bash)
|
|
358
|
+
|
|
359
|
+
# Separar stdout y stderr
|
|
360
|
+
command > stdout.log 2> stderr.log
|
|
361
|
+
|
|
362
|
+
# Descartar output
|
|
363
|
+
command > /dev/null # Ignorar stdout
|
|
364
|
+
command 2> /dev/null # Ignorar stderr
|
|
365
|
+
command &> /dev/null # Ignorar todo
|
|
366
|
+
|
|
367
|
+
# Here document
|
|
368
|
+
cat > config.yml <<EOF
|
|
369
|
+
database:
|
|
370
|
+
host: localhost
|
|
371
|
+
port: 5432
|
|
372
|
+
name: $DB_NAME
|
|
373
|
+
EOF
|
|
374
|
+
|
|
375
|
+
# Here string
|
|
376
|
+
grep "error" <<< "$LOG_CONTENT"
|
|
377
|
+
|
|
378
|
+
# Process substitution
|
|
379
|
+
diff <(cat file1.txt) <(cat file2.txt)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Comandos Útiles
|
|
383
|
+
|
|
384
|
+
### grep
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
#!/bin/bash
|
|
388
|
+
|
|
389
|
+
# Búsqueda básica
|
|
390
|
+
grep "error" app.log
|
|
391
|
+
grep -i "error" app.log # Case insensitive
|
|
392
|
+
grep -n "error" app.log # Mostrar números de línea
|
|
393
|
+
grep -c "error" app.log # Contar coincidencias
|
|
394
|
+
grep -v "debug" app.log # Invertir (excluir)
|
|
395
|
+
|
|
396
|
+
# Regex
|
|
397
|
+
grep -E "error|warning" app.log # Extended regex
|
|
398
|
+
grep "user_[0-9]+" app.log # Pattern con números
|
|
399
|
+
|
|
400
|
+
# Archivos
|
|
401
|
+
grep -r "TODO" app/ # Recursivo
|
|
402
|
+
grep -l "class User" app/models/ # Solo nombres de archivo
|
|
403
|
+
grep -L "test" spec/ # Archivos sin match
|
|
404
|
+
|
|
405
|
+
# Contexto
|
|
406
|
+
grep -A 3 "error" app.log # 3 líneas después
|
|
407
|
+
grep -B 3 "error" app.log # 3 líneas antes
|
|
408
|
+
grep -C 3 "error" app.log # 3 líneas antes y después
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### awk
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
#!/bin/bash
|
|
415
|
+
|
|
416
|
+
# Imprimir columnas
|
|
417
|
+
awk '{print $1}' file.txt # Primera columna
|
|
418
|
+
awk '{print $1, $3}' file.txt # Columnas 1 y 3
|
|
419
|
+
awk '{print $NF}' file.txt # Última columna
|
|
420
|
+
|
|
421
|
+
# Con delimitador
|
|
422
|
+
awk -F: '{print $1}' /etc/passwd # Delimitador :
|
|
423
|
+
awk -F',' '{print $2}' data.csv # Delimitador ,
|
|
424
|
+
|
|
425
|
+
# Condiciones
|
|
426
|
+
awk '$3 > 100 {print $1}' data.txt
|
|
427
|
+
awk '/error/ {print}' app.log
|
|
428
|
+
|
|
429
|
+
# Cálculos
|
|
430
|
+
awk '{sum += $1} END {print sum}' numbers.txt
|
|
431
|
+
awk '{count++} END {print count}' file.txt
|
|
432
|
+
|
|
433
|
+
# Variables
|
|
434
|
+
awk -v threshold=100 '$3 > threshold {print}' data.txt
|
|
435
|
+
|
|
436
|
+
# Ejemplo: analizar logs de Rails
|
|
437
|
+
awk '/Completed [45][0-9]{2}/ {print $4, $0}' production.log
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### sed
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
#!/bin/bash
|
|
444
|
+
|
|
445
|
+
# Reemplazar texto
|
|
446
|
+
sed 's/old/new/' file.txt # Primera ocurrencia por línea
|
|
447
|
+
sed 's/old/new/g' file.txt # Todas las ocurrencias
|
|
448
|
+
sed -i 's/old/new/g' file.txt # In-place (modifica archivo)
|
|
449
|
+
sed -i.bak 's/old/new/g' file.txt # Con backup
|
|
450
|
+
|
|
451
|
+
# Eliminar líneas
|
|
452
|
+
sed '/pattern/d' file.txt # Líneas con pattern
|
|
453
|
+
sed '5d' file.txt # Línea 5
|
|
454
|
+
sed '1,10d' file.txt # Líneas 1-10
|
|
455
|
+
|
|
456
|
+
# Insertar/añadir
|
|
457
|
+
sed '3i\New line' file.txt # Insertar antes de línea 3
|
|
458
|
+
sed '3a\New line' file.txt # Añadir después de línea 3
|
|
459
|
+
|
|
460
|
+
# Múltiples comandos
|
|
461
|
+
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
|
|
462
|
+
|
|
463
|
+
# Ejemplo: actualizar config
|
|
464
|
+
sed -i "s/DB_HOST=.*/DB_HOST=$NEW_HOST/" .env
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### xargs
|
|
468
|
+
|
|
469
|
+
```bash
|
|
470
|
+
#!/bin/bash
|
|
471
|
+
|
|
472
|
+
# Ejecutar comando con cada línea
|
|
473
|
+
cat files.txt | xargs rm
|
|
474
|
+
find . -name "*.log" | xargs rm
|
|
475
|
+
|
|
476
|
+
# Con placeholder
|
|
477
|
+
cat servers.txt | xargs -I {} ssh {} "uptime"
|
|
478
|
+
|
|
479
|
+
# Paralelo
|
|
480
|
+
cat urls.txt | xargs -P 4 -I {} curl -s {}
|
|
481
|
+
|
|
482
|
+
# Con confirmación
|
|
483
|
+
find . -name "*.tmp" | xargs -p rm
|
|
484
|
+
|
|
485
|
+
# Manejar espacios en nombres
|
|
486
|
+
find . -name "*.rb" -print0 | xargs -0 wc -l
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### find
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
#!/bin/bash
|
|
493
|
+
|
|
494
|
+
# Por nombre
|
|
495
|
+
find . -name "*.rb" # Archivos .rb
|
|
496
|
+
find . -iname "*.rb" # Case insensitive
|
|
497
|
+
find . -name "user*" # Empiezan con user
|
|
498
|
+
|
|
499
|
+
# Por tipo
|
|
500
|
+
find . -type f # Solo archivos
|
|
501
|
+
find . -type d # Solo directorios
|
|
502
|
+
|
|
503
|
+
# Por tiempo
|
|
504
|
+
find . -mtime -7 # Modificados últimos 7 días
|
|
505
|
+
find . -mmin -60 # Modificados última hora
|
|
506
|
+
|
|
507
|
+
# Por tamaño
|
|
508
|
+
find . -size +10M # Mayores de 10MB
|
|
509
|
+
find . -size -1k # Menores de 1KB
|
|
510
|
+
|
|
511
|
+
# Ejecutar comando
|
|
512
|
+
find . -name "*.rb" -exec wc -l {} \;
|
|
513
|
+
find . -name "*.log" -exec rm {} +
|
|
514
|
+
|
|
515
|
+
# Combinaciones
|
|
516
|
+
find app -name "*.rb" -type f -mtime -7
|
|
517
|
+
|
|
518
|
+
# Excluir directorios
|
|
519
|
+
find . -name "*.rb" -not -path "./vendor/*"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## Script Structure
|
|
523
|
+
|
|
524
|
+
### Shebang y header
|
|
525
|
+
|
|
526
|
+
```bash
|
|
527
|
+
#!/bin/bash
|
|
528
|
+
#
|
|
529
|
+
# Script: deploy.sh
|
|
530
|
+
# Description: Deploy Rails application
|
|
531
|
+
# Author: Your Name
|
|
532
|
+
# Date: 2024-01-15
|
|
533
|
+
# Usage: ./deploy.sh [environment]
|
|
534
|
+
#
|
|
535
|
+
|
|
536
|
+
set -euo pipefail # Exit on error, undefined vars, pipe failures
|
|
537
|
+
IFS=$'\n\t' # Safer word splitting
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Exit codes
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
#!/bin/bash
|
|
544
|
+
|
|
545
|
+
# Códigos estándar
|
|
546
|
+
# 0 = éxito
|
|
547
|
+
# 1 = error general
|
|
548
|
+
# 2 = uso incorrecto
|
|
549
|
+
|
|
550
|
+
deploy() {
|
|
551
|
+
if [[ -z "$1" ]]; then
|
|
552
|
+
echo "Error: Environment required" >&2
|
|
553
|
+
exit 2
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
if ! ssh "$1" "cd /app && git pull"; then
|
|
557
|
+
echo "Error: Deployment failed" >&2
|
|
558
|
+
exit 1
|
|
559
|
+
fi
|
|
560
|
+
|
|
561
|
+
echo "Deployment successful"
|
|
562
|
+
exit 0
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
deploy "$@"
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Error handling
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
#!/bin/bash
|
|
572
|
+
set -euo pipefail
|
|
573
|
+
|
|
574
|
+
# Trap para cleanup
|
|
575
|
+
cleanup() {
|
|
576
|
+
local exit_code=$?
|
|
577
|
+
echo "Cleaning up..."
|
|
578
|
+
rm -f /tmp/deploy.lock
|
|
579
|
+
exit $exit_code
|
|
580
|
+
}
|
|
581
|
+
trap cleanup EXIT
|
|
582
|
+
|
|
583
|
+
# Trap para errores
|
|
584
|
+
on_error() {
|
|
585
|
+
echo "Error on line $1" >&2
|
|
586
|
+
}
|
|
587
|
+
trap 'on_error $LINENO' ERR
|
|
588
|
+
|
|
589
|
+
# Verificar dependencias
|
|
590
|
+
check_dependencies() {
|
|
591
|
+
local deps=("git" "ruby" "bundle")
|
|
592
|
+
for dep in "${deps[@]}"; do
|
|
593
|
+
if ! command -v "$dep" &> /dev/null; then
|
|
594
|
+
echo "Error: $dep is required but not installed" >&2
|
|
595
|
+
exit 1
|
|
596
|
+
fi
|
|
597
|
+
done
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
# Función con manejo de errores
|
|
601
|
+
safe_deploy() {
|
|
602
|
+
local server=$1
|
|
603
|
+
|
|
604
|
+
echo "Deploying to $server..."
|
|
605
|
+
|
|
606
|
+
if ! ssh "$server" "cd /app && git pull origin main"; then
|
|
607
|
+
echo "Git pull failed" >&2
|
|
608
|
+
return 1
|
|
609
|
+
fi
|
|
610
|
+
|
|
611
|
+
if ! ssh "$server" "cd /app && bundle install"; then
|
|
612
|
+
echo "Bundle install failed" >&2
|
|
613
|
+
return 1
|
|
614
|
+
fi
|
|
615
|
+
|
|
616
|
+
return 0
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
# Main
|
|
620
|
+
main() {
|
|
621
|
+
check_dependencies
|
|
622
|
+
|
|
623
|
+
for server in "${SERVERS[@]}"; do
|
|
624
|
+
if ! safe_deploy "$server"; then
|
|
625
|
+
echo "Deployment to $server failed, aborting" >&2
|
|
626
|
+
exit 1
|
|
627
|
+
fi
|
|
628
|
+
done
|
|
629
|
+
|
|
630
|
+
echo "All deployments successful!"
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
main "$@"
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
## Variables de Entorno
|
|
637
|
+
|
|
638
|
+
### Export y acceso
|
|
639
|
+
|
|
640
|
+
```bash
|
|
641
|
+
#!/bin/bash
|
|
642
|
+
|
|
643
|
+
# Definir variables de entorno
|
|
644
|
+
export RAILS_ENV="production"
|
|
645
|
+
export DATABASE_URL="postgres://localhost/myapp"
|
|
646
|
+
|
|
647
|
+
# Cargar desde archivo
|
|
648
|
+
set -a # Auto-export
|
|
649
|
+
source .env
|
|
650
|
+
set +a
|
|
651
|
+
|
|
652
|
+
# O manualmente
|
|
653
|
+
while IFS='=' read -r key value; do
|
|
654
|
+
# Ignorar comentarios y líneas vacías
|
|
655
|
+
[[ $key =~ ^#.*$ ]] && continue
|
|
656
|
+
[[ -z "$key" ]] && continue
|
|
657
|
+
export "$key=$value"
|
|
658
|
+
done < .env
|
|
659
|
+
|
|
660
|
+
# Verificar si está definida
|
|
661
|
+
if [[ -v DATABASE_URL ]]; then
|
|
662
|
+
echo "DATABASE_URL is set"
|
|
663
|
+
fi
|
|
664
|
+
|
|
665
|
+
# Unset
|
|
666
|
+
unset TEMP_VAR
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### dotenv
|
|
670
|
+
|
|
671
|
+
```bash
|
|
672
|
+
# .env
|
|
673
|
+
RAILS_ENV=production
|
|
674
|
+
DATABASE_URL=postgres://localhost/myapp
|
|
675
|
+
SECRET_KEY_BASE=abc123
|
|
676
|
+
REDIS_URL=redis://localhost:6379
|
|
677
|
+
|
|
678
|
+
# .env.local (no commitear)
|
|
679
|
+
AWS_ACCESS_KEY_ID=AKIA...
|
|
680
|
+
AWS_SECRET_ACCESS_KEY=...
|
|
681
|
+
|
|
682
|
+
# .env.example (commitear como template)
|
|
683
|
+
RAILS_ENV=development
|
|
684
|
+
DATABASE_URL=
|
|
685
|
+
SECRET_KEY_BASE=
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
```bash
|
|
689
|
+
#!/bin/bash
|
|
690
|
+
# Función para cargar .env
|
|
691
|
+
load_env() {
|
|
692
|
+
local env_file=${1:-.env}
|
|
693
|
+
|
|
694
|
+
if [[ ! -f "$env_file" ]]; then
|
|
695
|
+
echo "Warning: $env_file not found" >&2
|
|
696
|
+
return 1
|
|
697
|
+
fi
|
|
698
|
+
|
|
699
|
+
while IFS='=' read -r key value; do
|
|
700
|
+
# Trim whitespace
|
|
701
|
+
key=$(echo "$key" | xargs)
|
|
702
|
+
value=$(echo "$value" | xargs)
|
|
703
|
+
|
|
704
|
+
# Skip comments and empty lines
|
|
705
|
+
[[ -z "$key" || $key == \#* ]] && continue
|
|
706
|
+
|
|
707
|
+
# Remove quotes from value
|
|
708
|
+
value="${value%\"}"
|
|
709
|
+
value="${value#\"}"
|
|
710
|
+
|
|
711
|
+
export "$key=$value"
|
|
712
|
+
done < "$env_file"
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
load_env ".env"
|
|
716
|
+
load_env ".env.local" 2>/dev/null || true
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
## Cron Jobs
|
|
720
|
+
|
|
721
|
+
### Sintaxis de crontab
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
# ┌───────────── minuto (0 - 59)
|
|
725
|
+
# │ ┌───────────── hora (0 - 23)
|
|
726
|
+
# │ │ ┌───────────── día del mes (1 - 31)
|
|
727
|
+
# │ │ │ ┌───────────── mes (1 - 12)
|
|
728
|
+
# │ │ │ │ ┌───────────── día de la semana (0 - 6) (Domingo = 0)
|
|
729
|
+
# │ │ │ │ │
|
|
730
|
+
# * * * * * comando
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### Ejemplos comunes
|
|
734
|
+
|
|
735
|
+
```bash
|
|
736
|
+
# crontab -e
|
|
737
|
+
|
|
738
|
+
# Cada minuto
|
|
739
|
+
* * * * * /app/scripts/check_health.sh
|
|
740
|
+
|
|
741
|
+
# Cada 5 minutos
|
|
742
|
+
*/5 * * * * /app/scripts/sync_data.sh
|
|
743
|
+
|
|
744
|
+
# Cada hora
|
|
745
|
+
0 * * * * /app/scripts/hourly_task.sh
|
|
746
|
+
|
|
747
|
+
# Diario a las 2:00 AM
|
|
748
|
+
0 2 * * * /app/scripts/daily_backup.sh
|
|
749
|
+
|
|
750
|
+
# Lunes a las 9:00 AM
|
|
751
|
+
0 9 * * 1 /app/scripts/weekly_report.sh
|
|
752
|
+
|
|
753
|
+
# Primer día del mes
|
|
754
|
+
0 0 1 * * /app/scripts/monthly_cleanup.sh
|
|
755
|
+
|
|
756
|
+
# Múltiples horarios
|
|
757
|
+
0 8,12,18 * * * /app/scripts/three_times_daily.sh
|
|
758
|
+
|
|
759
|
+
# Rango
|
|
760
|
+
0 9-17 * * 1-5 /app/scripts/business_hours.sh
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
### Whenever gem (Ruby)
|
|
764
|
+
|
|
765
|
+
```ruby
|
|
766
|
+
# Gemfile
|
|
767
|
+
gem "whenever", require: false
|
|
768
|
+
|
|
769
|
+
# config/schedule.rb
|
|
770
|
+
set :output, "log/cron.log"
|
|
771
|
+
set :environment, "production"
|
|
772
|
+
|
|
773
|
+
# Cada día a las 2am
|
|
774
|
+
every 1.day, at: "2:00 am" do
|
|
775
|
+
rake "db:backup"
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
# Cada hora
|
|
779
|
+
every 1.hour do
|
|
780
|
+
runner "DataSync.perform"
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
# Cada 5 minutos
|
|
784
|
+
every 5.minutes do
|
|
785
|
+
rake "health:check"
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
# Solo en producción
|
|
789
|
+
if environment == "production"
|
|
790
|
+
every 1.day, at: "4:00 am" do
|
|
791
|
+
rake "cleanup:old_sessions"
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
```bash
|
|
797
|
+
# Generar crontab
|
|
798
|
+
bundle exec whenever
|
|
799
|
+
|
|
800
|
+
# Instalar en crontab
|
|
801
|
+
bundle exec whenever --update-crontab myapp
|
|
802
|
+
|
|
803
|
+
# Eliminar de crontab
|
|
804
|
+
bundle exec whenever --clear-crontab myapp
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
## Aliases y Funciones (.bashrc/.zshrc)
|
|
808
|
+
|
|
809
|
+
```bash
|
|
810
|
+
# ~/.bashrc o ~/.zshrc
|
|
811
|
+
|
|
812
|
+
# Aliases para Rails
|
|
813
|
+
alias be="bundle exec"
|
|
814
|
+
alias rs="bundle exec rails server"
|
|
815
|
+
alias rc="bundle exec rails console"
|
|
816
|
+
alias rr="bundle exec rails routes"
|
|
817
|
+
alias rdbm="bundle exec rails db:migrate"
|
|
818
|
+
alias rdbr="bundle exec rails db:rollback"
|
|
819
|
+
alias rdbs="bundle exec rails db:seed"
|
|
820
|
+
alias rspec="bundle exec rspec"
|
|
821
|
+
|
|
822
|
+
# Alias para Git
|
|
823
|
+
alias gs="git status"
|
|
824
|
+
alias gd="git diff"
|
|
825
|
+
alias gc="git commit"
|
|
826
|
+
alias gp="git push"
|
|
827
|
+
alias gl="git pull"
|
|
828
|
+
alias gco="git checkout"
|
|
829
|
+
alias gb="git branch"
|
|
830
|
+
alias glog="git log --oneline --graph --decorate -20"
|
|
831
|
+
|
|
832
|
+
# Funciones útiles
|
|
833
|
+
# Crear y cambiar a directorio
|
|
834
|
+
mkcd() {
|
|
835
|
+
mkdir -p "$1" && cd "$1"
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
# Buscar en archivos Ruby
|
|
839
|
+
rgr() {
|
|
840
|
+
grep -rn "$1" --include="*.rb" .
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
# Rails: reset database
|
|
844
|
+
dbreset() {
|
|
845
|
+
bundle exec rails db:drop db:create db:migrate db:seed
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
# Git: crear branch y pushear
|
|
849
|
+
gcb() {
|
|
850
|
+
git checkout -b "$1" && git push -u origin "$1"
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
# Docker: entrar a contenedor
|
|
854
|
+
dexec() {
|
|
855
|
+
docker exec -it "$1" /bin/bash
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
# Logs de Rails en tiempo real
|
|
859
|
+
railslogs() {
|
|
860
|
+
tail -f log/"${RAILS_ENV:-development}".log
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
# Matar proceso en puerto
|
|
864
|
+
killport() {
|
|
865
|
+
lsof -ti:"$1" | xargs kill -9
|
|
866
|
+
}
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
## Scripts Útiles para Rails
|
|
870
|
+
|
|
871
|
+
### Deploy script
|
|
872
|
+
|
|
873
|
+
```bash
|
|
874
|
+
#!/bin/bash
|
|
875
|
+
# scripts/deploy.sh
|
|
876
|
+
|
|
877
|
+
set -euo pipefail
|
|
878
|
+
|
|
879
|
+
APP_DIR="/var/www/myapp"
|
|
880
|
+
BRANCH="${1:-main}"
|
|
881
|
+
RAILS_ENV="${RAILS_ENV:-production}"
|
|
882
|
+
|
|
883
|
+
echo "=== Deploying $BRANCH to $RAILS_ENV ==="
|
|
884
|
+
|
|
885
|
+
cd "$APP_DIR"
|
|
886
|
+
|
|
887
|
+
echo "-> Pulling latest code..."
|
|
888
|
+
git fetch origin
|
|
889
|
+
git checkout "$BRANCH"
|
|
890
|
+
git pull origin "$BRANCH"
|
|
891
|
+
|
|
892
|
+
echo "-> Installing dependencies..."
|
|
893
|
+
bundle install --deployment --without development test
|
|
894
|
+
|
|
895
|
+
echo "-> Compiling assets..."
|
|
896
|
+
RAILS_ENV=$RAILS_ENV bundle exec rails assets:precompile
|
|
897
|
+
|
|
898
|
+
echo "-> Running migrations..."
|
|
899
|
+
RAILS_ENV=$RAILS_ENV bundle exec rails db:migrate
|
|
900
|
+
|
|
901
|
+
echo "-> Restarting application..."
|
|
902
|
+
sudo systemctl restart myapp
|
|
903
|
+
|
|
904
|
+
echo "-> Warming up..."
|
|
905
|
+
sleep 5
|
|
906
|
+
curl -s http://localhost:3000/health || exit 1
|
|
907
|
+
|
|
908
|
+
echo "=== Deployment complete! ==="
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
### Backup script
|
|
912
|
+
|
|
913
|
+
```bash
|
|
914
|
+
#!/bin/bash
|
|
915
|
+
# scripts/backup.sh
|
|
916
|
+
|
|
917
|
+
set -euo pipefail
|
|
918
|
+
|
|
919
|
+
# Configuration
|
|
920
|
+
BACKUP_DIR="/backups"
|
|
921
|
+
DB_PATH="/app/storage/production.sqlite3"
|
|
922
|
+
RETENTION_DAYS=30
|
|
923
|
+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
924
|
+
|
|
925
|
+
echo "=== Starting backup ==="
|
|
926
|
+
|
|
927
|
+
# Create backup directory
|
|
928
|
+
mkdir -p "$BACKUP_DIR"
|
|
929
|
+
|
|
930
|
+
# Database backup
|
|
931
|
+
echo "-> Backing up database..."
|
|
932
|
+
cp "$DB_PATH" "$BACKUP_DIR/db_$TIMESTAMP.sqlite3"
|
|
933
|
+
|
|
934
|
+
# Compress
|
|
935
|
+
gzip "$BACKUP_DIR/db_$TIMESTAMP.sqlite3"
|
|
936
|
+
|
|
937
|
+
# Upload backup
|
|
938
|
+
echo "-> Uploading to S3..."
|
|
939
|
+
aws s3 cp "$BACKUP_DIR/db_$TIMESTAMP.sqlite3.gz" \
|
|
940
|
+
"s3://myapp-backups/database/"
|
|
941
|
+
|
|
942
|
+
# Cleanup old backups
|
|
943
|
+
echo "-> Cleaning old backups..."
|
|
944
|
+
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
|
|
945
|
+
|
|
946
|
+
echo "=== Backup complete: db_$TIMESTAMP.sqlite3.gz ==="
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
### Migrate script
|
|
950
|
+
|
|
951
|
+
```bash
|
|
952
|
+
#!/bin/bash
|
|
953
|
+
# scripts/migrate.sh
|
|
954
|
+
|
|
955
|
+
set -euo pipefail
|
|
956
|
+
|
|
957
|
+
RAILS_ENV="${RAILS_ENV:-production}"
|
|
958
|
+
|
|
959
|
+
echo "=== Running migrations for $RAILS_ENV ==="
|
|
960
|
+
|
|
961
|
+
# Check pending migrations
|
|
962
|
+
PENDING=$(RAILS_ENV=$RAILS_ENV bundle exec rails db:migrate:status | grep "down" | wc -l)
|
|
963
|
+
|
|
964
|
+
if [[ $PENDING -eq 0 ]]; then
|
|
965
|
+
echo "No pending migrations"
|
|
966
|
+
exit 0
|
|
967
|
+
fi
|
|
968
|
+
|
|
969
|
+
echo "Found $PENDING pending migrations"
|
|
970
|
+
|
|
971
|
+
# Backup before migration
|
|
972
|
+
echo "-> Creating backup..."
|
|
973
|
+
cp storage/production.sqlite3 "storage/pre_migration_$(date +%Y%m%d_%H%M%S).sqlite3"
|
|
974
|
+
|
|
975
|
+
# Run migrations
|
|
976
|
+
echo "-> Running migrations..."
|
|
977
|
+
RAILS_ENV=$RAILS_ENV bundle exec rails db:migrate
|
|
978
|
+
|
|
979
|
+
# Verify
|
|
980
|
+
echo "-> Verifying..."
|
|
981
|
+
REMAINING=$(RAILS_ENV=$RAILS_ENV bundle exec rails db:migrate:status | grep "down" | wc -l)
|
|
982
|
+
|
|
983
|
+
if [[ $REMAINING -gt 0 ]]; then
|
|
984
|
+
echo "ERROR: $REMAINING migrations still pending!"
|
|
985
|
+
exit 1
|
|
986
|
+
fi
|
|
987
|
+
|
|
988
|
+
echo "=== Migrations complete ==="
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
### Health check script
|
|
992
|
+
|
|
993
|
+
```bash
|
|
994
|
+
#!/bin/bash
|
|
995
|
+
# scripts/health_check.sh
|
|
996
|
+
|
|
997
|
+
set -euo pipefail
|
|
998
|
+
|
|
999
|
+
URL="${1:-http://localhost:3000/up}"
|
|
1000
|
+
TIMEOUT=10
|
|
1001
|
+
RETRIES=3
|
|
1002
|
+
|
|
1003
|
+
check_health() {
|
|
1004
|
+
curl -sf --max-time $TIMEOUT "$URL" > /dev/null
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
for i in $(seq 1 $RETRIES); do
|
|
1008
|
+
if check_health; then
|
|
1009
|
+
echo "Health check passed"
|
|
1010
|
+
exit 0
|
|
1011
|
+
fi
|
|
1012
|
+
echo "Attempt $i failed, retrying..."
|
|
1013
|
+
sleep 2
|
|
1014
|
+
done
|
|
1015
|
+
|
|
1016
|
+
echo "Health check failed after $RETRIES attempts"
|
|
1017
|
+
exit 1
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
### Console wrapper
|
|
1021
|
+
|
|
1022
|
+
```bash
|
|
1023
|
+
#!/bin/bash
|
|
1024
|
+
# scripts/console.sh
|
|
1025
|
+
|
|
1026
|
+
set -euo pipefail
|
|
1027
|
+
|
|
1028
|
+
RAILS_ENV="${1:-production}"
|
|
1029
|
+
|
|
1030
|
+
echo "Opening Rails console for $RAILS_ENV"
|
|
1031
|
+
echo "Type 'exit' to quit"
|
|
1032
|
+
echo ""
|
|
1033
|
+
|
|
1034
|
+
if [[ $RAILS_ENV == "production" ]]; then
|
|
1035
|
+
echo "WARNING: You are in PRODUCTION console!"
|
|
1036
|
+
echo "Be careful with data modifications."
|
|
1037
|
+
echo ""
|
|
1038
|
+
read -p "Are you sure? (yes/no): " confirm
|
|
1039
|
+
[[ $confirm != "yes" ]] && exit 1
|
|
1040
|
+
fi
|
|
1041
|
+
|
|
1042
|
+
RAILS_ENV=$RAILS_ENV bundle exec rails console
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
## Template de Script
|
|
1046
|
+
|
|
1047
|
+
```bash
|
|
1048
|
+
#!/bin/bash
|
|
1049
|
+
#
|
|
1050
|
+
# Script: script_name.sh
|
|
1051
|
+
# Description: Brief description
|
|
1052
|
+
# Usage: ./script_name.sh [options] <arguments>
|
|
1053
|
+
#
|
|
1054
|
+
|
|
1055
|
+
set -euo pipefail
|
|
1056
|
+
|
|
1057
|
+
# ==============================================================================
|
|
1058
|
+
# Configuration
|
|
1059
|
+
# ==============================================================================
|
|
1060
|
+
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
1061
|
+
readonly SCRIPT_NAME="$(basename "$0")"
|
|
1062
|
+
|
|
1063
|
+
# ==============================================================================
|
|
1064
|
+
# Functions
|
|
1065
|
+
# ==============================================================================
|
|
1066
|
+
usage() {
|
|
1067
|
+
cat <<EOF
|
|
1068
|
+
Usage: $SCRIPT_NAME [options] <argument>
|
|
1069
|
+
|
|
1070
|
+
Options:
|
|
1071
|
+
-h, --help Show this help message
|
|
1072
|
+
-v, --verbose Enable verbose output
|
|
1073
|
+
-e, --env Environment (default: development)
|
|
1074
|
+
|
|
1075
|
+
Examples:
|
|
1076
|
+
$SCRIPT_NAME -e production
|
|
1077
|
+
$SCRIPT_NAME --verbose
|
|
1078
|
+
|
|
1079
|
+
EOF
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
log() {
|
|
1083
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
error() {
|
|
1087
|
+
echo "[ERROR] $*" >&2
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
cleanup() {
|
|
1091
|
+
# Cleanup tasks
|
|
1092
|
+
:
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
# ==============================================================================
|
|
1096
|
+
# Main
|
|
1097
|
+
# ==============================================================================
|
|
1098
|
+
main() {
|
|
1099
|
+
local verbose=false
|
|
1100
|
+
local env="development"
|
|
1101
|
+
|
|
1102
|
+
# Parse arguments
|
|
1103
|
+
while [[ $# -gt 0 ]]; do
|
|
1104
|
+
case "$1" in
|
|
1105
|
+
-h|--help)
|
|
1106
|
+
usage
|
|
1107
|
+
exit 0
|
|
1108
|
+
;;
|
|
1109
|
+
-v|--verbose)
|
|
1110
|
+
verbose=true
|
|
1111
|
+
shift
|
|
1112
|
+
;;
|
|
1113
|
+
-e|--env)
|
|
1114
|
+
env="$2"
|
|
1115
|
+
shift 2
|
|
1116
|
+
;;
|
|
1117
|
+
*)
|
|
1118
|
+
error "Unknown option: $1"
|
|
1119
|
+
usage
|
|
1120
|
+
exit 1
|
|
1121
|
+
;;
|
|
1122
|
+
esac
|
|
1123
|
+
done
|
|
1124
|
+
|
|
1125
|
+
trap cleanup EXIT
|
|
1126
|
+
|
|
1127
|
+
# Script logic here
|
|
1128
|
+
log "Starting script with env=$env verbose=$verbose"
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
main "$@"
|
|
1132
|
+
```
|