Skip to content

Commit a3ab333

Browse files
author
Developer
committed
Add deployment config for digitalocean
1 parent eb3551b commit a3ab333

26 files changed

+4388
-497
lines changed

.env.example

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,70 @@
1+
# StreamSource Environment Variables - Development
2+
# Copy this file to .env for local development
3+
4+
# ============================================
5+
# Core Rails Configuration
6+
# ============================================
7+
8+
# Rails environment (development, test, production)
9+
RAILS_ENV=development
10+
11+
# Secret key base for development (generate with: rails secret)
12+
SECRET_KEY_BASE=development-secret-key-base-change-in-production
13+
14+
# Enable/disable logging to stdout
15+
RAILS_LOG_TO_STDOUT=true
16+
17+
# Log level (debug, info, warn, error, fatal)
18+
RAILS_LOG_LEVEL=debug
19+
20+
# ============================================
121
# Database Configuration
2-
DATABASE_URL=postgres://streamsource:password@localhost:5432/streamsource_development
22+
# ============================================
323

24+
# PostgreSQL connection URL
25+
DATABASE_URL=postgres://streamsource:streamsource_password@localhost:5432/streamsource_development
26+
27+
# ============================================
428
# Redis Configuration
29+
# ============================================
30+
31+
# Redis connection URL (used for ActionCable, caching, and session storage)
532
REDIS_URL=redis://localhost:6379/0
633

7-
# Rails Configuration
8-
RAILS_ENV=development
9-
SECRET_KEY_BASE=your-secret-key-base-here
10-
RAILS_LOG_TO_STDOUT=true
34+
# ============================================
35+
# Application Server Configuration
36+
# ============================================
1137

12-
# Application Configuration
38+
# Maximum number of threads per Puma worker
1339
RAILS_MAX_THREADS=5
40+
41+
# Number of Puma worker processes
1442
WEB_CONCURRENCY=2
1543

16-
# Optional: External Services
17-
# SENTRY_DSN=your-sentry-dsn
44+
# Port for the web server to listen on
45+
PORT=3000
46+
47+
# ============================================
48+
# Optional External Services
49+
# ============================================
50+
51+
# Sentry error tracking (https://sentry.io)
52+
# SENTRY_DSN=https://[email protected]/your-project-id
53+
54+
# ============================================
55+
# Feature Flags (Optional)
56+
# ============================================
57+
58+
# These can also be managed via Flipper UI at /admin/feature_flags
59+
# ENABLE_ANALYTICS=false
60+
# ENABLE_BULK_IMPORT=false
61+
# ENABLE_EXPORT=false
62+
# ENABLE_WEBHOOKS=false
63+
64+
# ============================================
65+
# Development-Specific Settings
66+
# ============================================
67+
68+
# Bundle configuration (usually not needed to change)
69+
# BUNDLE_WITHOUT=""
70+
# BUNDLE_GEMFILE="Gemfile"

.github/dependabot.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
version: 2
2+
updates:
3+
# Ruby dependencies
4+
- package-ecosystem: "bundler"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
day: "monday"
9+
time: "09:00"
10+
open-pull-requests-limit: 10
11+
groups:
12+
rails:
13+
patterns:
14+
- "rails*"
15+
- "actioncable"
16+
- "actionmailbox"
17+
- "actionmailer"
18+
- "actionpack"
19+
- "actiontext"
20+
- "actionview"
21+
- "activejob"
22+
- "activemodel"
23+
- "activerecord"
24+
- "activestorage"
25+
- "activesupport"
26+
testing:
27+
patterns:
28+
- "rspec*"
29+
- "factory_bot*"
30+
- "faker"
31+
- "shoulda-matchers"
32+
- "database_cleaner*"
33+
- "simplecov"
34+
- "webmock"
35+
- "vcr"
36+
37+
# JavaScript dependencies
38+
- package-ecosystem: "npm"
39+
directory: "/"
40+
schedule:
41+
interval: "weekly"
42+
day: "monday"
43+
time: "09:00"
44+
open-pull-requests-limit: 10
45+
groups:
46+
hotwire:
47+
patterns:
48+
- "@hotwired/*"
49+
- "turbo*"
50+
- "stimulus*"
51+
52+
# GitHub Actions
53+
- package-ecosystem: "github-actions"
54+
directory: "/"
55+
schedule:
56+
interval: "weekly"
57+
day: "monday"
58+
time: "09:00"

.github/workflows/deploy.yml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: Deploy to DigitalOcean
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
workflow_dispatch:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
12+
services:
13+
postgres:
14+
image: postgres:17
15+
env:
16+
POSTGRES_PASSWORD: postgres
17+
options: >-
18+
--health-cmd pg_isready
19+
--health-interval 10s
20+
--health-timeout 5s
21+
--health-retries 5
22+
ports:
23+
- 5432:5432
24+
25+
redis:
26+
image: redis:7
27+
options: >-
28+
--health-cmd "redis-cli ping"
29+
--health-interval 10s
30+
--health-timeout 5s
31+
--health-retries 5
32+
ports:
33+
- 6379:6379
34+
35+
steps:
36+
- uses: actions/checkout@v4
37+
38+
- name: Set up Ruby
39+
uses: ruby/setup-ruby@v1
40+
with:
41+
ruby-version: '3.3.6'
42+
bundler-cache: true
43+
44+
- name: Setup Node
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: '20'
48+
cache: 'yarn'
49+
50+
- name: Install dependencies
51+
run: |
52+
yarn install --frozen-lockfile
53+
54+
- name: Setup test database
55+
env:
56+
RAILS_ENV: test
57+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/streamsource_test
58+
REDIS_URL: redis://localhost:6379/1
59+
run: |
60+
bundle exec rails db:create
61+
bundle exec rails db:schema:load
62+
63+
- name: Run tests
64+
env:
65+
RAILS_ENV: test
66+
DATABASE_URL: postgres://postgres:postgres@localhost:5432/streamsource_test
67+
REDIS_URL: redis://localhost:6379/1
68+
run: bundle exec rspec
69+
70+
- name: Run security checks
71+
run: |
72+
bundle exec brakeman -q -w2
73+
bundle exec bundler-audit --update
74+
75+
deploy:
76+
needs: test
77+
runs-on: ubuntu-latest
78+
if: github.ref == 'refs/heads/main'
79+
80+
steps:
81+
- uses: actions/checkout@v4
82+
83+
- name: Deploy to DigitalOcean
84+
uses: appleboy/[email protected]
85+
with:
86+
host: ${{ secrets.DROPLET_HOST }}
87+
username: deploy
88+
key: ${{ secrets.DEPLOY_SSH_KEY }}
89+
script: |
90+
cd /var/www/streamsource
91+
./deploy/github-deploy.sh
92+
93+
- name: Health check
94+
run: |
95+
sleep 30
96+
curl -f https://${{ secrets.DROPLET_HOST }}/health || exit 1
97+
98+
- name: Notify deployment status
99+
if: always()
100+
uses: 8398a7/action-slack@v3
101+
with:
102+
status: ${{ job.status }}
103+
text: 'StreamSource deployment ${{ job.status }}'
104+
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
105+
continue-on-error: true
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Scheduled Power Management
2+
3+
on:
4+
schedule:
5+
# Power ON at 9 AM EST (14:00 UTC) Monday-Friday
6+
- cron: '0 14 * * 1-5'
7+
# Power OFF at 6 PM EST (23:00 UTC) Monday-Friday
8+
- cron: '0 23 * * 1-5'
9+
workflow_dispatch:
10+
inputs:
11+
action:
12+
description: 'Power action'
13+
required: true
14+
default: 'status'
15+
type: choice
16+
options:
17+
- status
18+
- power_on
19+
- power_off
20+
21+
jobs:
22+
power-management:
23+
runs-on: ubuntu-latest
24+
25+
steps:
26+
- name: Determine action
27+
id: determine-action
28+
run: |
29+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
30+
echo "action=${{ github.event.inputs.action }}" >> $GITHUB_OUTPUT
31+
else
32+
# Check current hour to determine if we should power on or off
33+
HOUR=$(date -u +%H)
34+
if [ "$HOUR" == "14" ]; then
35+
echo "action=power_on" >> $GITHUB_OUTPUT
36+
elif [ "$HOUR" == "23" ]; then
37+
echo "action=power_off" >> $GITHUB_OUTPUT
38+
else
39+
echo "action=status" >> $GITHUB_OUTPUT
40+
fi
41+
fi
42+
43+
- name: Check droplet status
44+
id: check-status
45+
run: |
46+
STATUS=$(curl -s -X GET \
47+
-H "Authorization: Bearer ${{ secrets.DO_API_TOKEN }}" \
48+
"https://api.digitalocean.com/v2/droplets/${{ secrets.DROPLET_ID }}" \
49+
| jq -r '.droplet.status')
50+
echo "Current status: $STATUS"
51+
echo "status=$STATUS" >> $GITHUB_OUTPUT
52+
53+
- name: Power ON droplet
54+
if: steps.determine-action.outputs.action == 'power_on' && steps.check-status.outputs.status != 'active'
55+
run: |
56+
echo "Powering ON droplet..."
57+
curl -s -X POST \
58+
-H "Content-Type: application/json" \
59+
-H "Authorization: Bearer ${{ secrets.DO_API_TOKEN }}" \
60+
"https://api.digitalocean.com/v2/droplets/${{ secrets.DROPLET_ID }}/actions" \
61+
-d '{"type":"power_on"}'
62+
63+
# Wait for droplet to be active
64+
for i in {1..30}; do
65+
sleep 10
66+
STATUS=$(curl -s -X GET \
67+
-H "Authorization: Bearer ${{ secrets.DO_API_TOKEN }}" \
68+
"https://api.digitalocean.com/v2/droplets/${{ secrets.DROPLET_ID }}" \
69+
| jq -r '.droplet.status')
70+
if [ "$STATUS" == "active" ]; then
71+
echo "Droplet is now active!"
72+
break
73+
fi
74+
echo "Waiting for droplet to be active... ($i/30)"
75+
done
76+
77+
- name: Power OFF droplet
78+
if: steps.determine-action.outputs.action == 'power_off' && steps.check-status.outputs.status == 'active'
79+
run: |
80+
# First, gracefully stop services via SSH
81+
echo "Gracefully stopping services..."
82+
ssh -o StrictHostKeyChecking=no \
83+
-i <(echo "${{ secrets.DEPLOY_SSH_KEY }}") \
84+
deploy@${{ secrets.DROPLET_HOST }} \
85+
"sudo systemctl stop puma nginx postgresql redis" || true
86+
87+
sleep 5
88+
89+
# Then power off the droplet
90+
echo "Powering OFF droplet..."
91+
curl -s -X POST \
92+
-H "Content-Type: application/json" \
93+
-H "Authorization: Bearer ${{ secrets.DO_API_TOKEN }}" \
94+
"https://api.digitalocean.com/v2/droplets/${{ secrets.DROPLET_ID }}/actions" \
95+
-d '{"type":"power_off"}'
96+
97+
- name: Report status
98+
if: always()
99+
run: |
100+
FINAL_STATUS=$(curl -s -X GET \
101+
-H "Authorization: Bearer ${{ secrets.DO_API_TOKEN }}" \
102+
"https://api.digitalocean.com/v2/droplets/${{ secrets.DROPLET_ID }}" \
103+
| jq -r '.droplet.status')
104+
echo "Final droplet status: $FINAL_STATUS"
105+
106+
# Optional: Send notification
107+
if [ -n "${{ secrets.SLACK_WEBHOOK }}" ]; then
108+
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
109+
-H 'Content-type: application/json' \
110+
-d "{\"text\":\"StreamSource droplet is now $FINAL_STATUS\"}"
111+
fi

0 commit comments

Comments
 (0)