Skip to content

Commit 55abf3a

Browse files
authored
Merge pull request #6 from hackdays-io/feature/deployment-pipeline
Configure deployment pipeline
2 parents 9b730e3 + d8d0d78 commit 55abf3a

File tree

7 files changed

+522
-0
lines changed

7 files changed

+522
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Backend Deployment
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'backend/**'
9+
- '.github/workflows/backend-deploy.yml'
10+
workflow_dispatch:
11+
12+
jobs:
13+
deploy:
14+
runs-on: ubuntu-latest
15+
defaults:
16+
run:
17+
working-directory: backend
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: '3.12'
26+
cache: 'pip'
27+
28+
- name: Install dependencies
29+
run: |
30+
python -m pip install --upgrade pip
31+
pip install flake8 pytest pytest-cov black isort
32+
pip install -r requirements.txt
33+
34+
- name: Run tests
35+
env:
36+
TESTING: "True"
37+
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/test_db"
38+
DATABASE_TEST_URL: "postgresql://postgres:postgres@localhost:5432/test_db"
39+
SECRET_KEY: "test-secret-key-for-ci-environment"
40+
AUTH0_DOMAIN: "example.auth0.com"
41+
AUTH0_CLIENT_ID: "test-client-id"
42+
AUTH0_CLIENT_SECRET: "test-client-secret"
43+
AUTH0_AUDIENCE: "https://api.example.com"
44+
OPENAI_API_KEY: "sk-test-key"
45+
run: pytest --cov=app --cov-report=xml
46+
47+
- name: Generate deployment package
48+
run: |
49+
mkdir -p deployment_package
50+
cp -r app deployment_package/
51+
cp -r scripts deployment_package/
52+
cp requirements.txt deployment_package/
53+
cp Procfile deployment_package/ || echo "No Procfile found, creating one"
54+
if [ ! -f deployment_package/Procfile ]; then
55+
echo "web: uvicorn app.main:app --host 0.0.0.0 --port \$PORT" > deployment_package/Procfile
56+
fi
57+
cd deployment_package && zip -r ../deployment_package.zip .
58+
59+
- name: Configure AWS credentials
60+
uses: aws-actions/configure-aws-credentials@v4
61+
with:
62+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
63+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
64+
aws-region: ${{ secrets.AWS_REGION }}
65+
66+
- name: Deploy to Elastic Beanstalk
67+
uses: einaregilsson/beanstalk-deploy@v21
68+
with:
69+
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
70+
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
71+
application_name: ${{ secrets.EB_APPLICATION_NAME }}
72+
environment_name: ${{ secrets.EB_ENVIRONMENT_NAME }}
73+
version_label: "ver-${{ github.sha }}"
74+
region: ${{ secrets.AWS_REGION }}
75+
deployment_package: deployment_package.zip
76+
wait_for_environment_recovery: 300
77+
78+
- name: Send deployment notification
79+
if: always()
80+
uses: slackapi/slack-github-action@v1
81+
with:
82+
payload: |
83+
{
84+
"text": "${{ job.status == 'success' && '✅ Backend deployed successfully' || '❌ Backend deployment failed' }}",
85+
"blocks": [
86+
{
87+
"type": "section",
88+
"text": {
89+
"type": "mrkdwn",
90+
"text": "${{ job.status == 'success' && '✅ Backend deployed successfully to Elastic Beanstalk' || '❌ Backend deployment failed' }}"
91+
}
92+
},
93+
{
94+
"type": "section",
95+
"fields": [
96+
{
97+
"type": "mrkdwn",
98+
"text": "*Environment:* ${{ secrets.EB_ENVIRONMENT_NAME }}"
99+
},
100+
{
101+
"type": "mrkdwn",
102+
"text": "*Version:* ver-${{ github.sha }}"
103+
}
104+
]
105+
},
106+
{
107+
"type": "section",
108+
"text": {
109+
"type": "mrkdwn",
110+
"text": "*Commit:* <${{ github.event.repository.html_url }}/commit/${{ github.sha }}|${{ github.sha }}>"
111+
}
112+
}
113+
]
114+
}
115+
env:
116+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
117+
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: Frontend Deployment
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'frontend/**'
9+
- '.github/workflows/frontend-deploy.yml'
10+
workflow_dispatch:
11+
12+
jobs:
13+
deploy:
14+
runs-on: ubuntu-latest
15+
defaults:
16+
run:
17+
working-directory: frontend
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Set up Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: '20'
26+
cache: 'npm'
27+
cache-dependency-path: frontend/package-lock.json
28+
29+
- name: Install dependencies
30+
run: npm install
31+
32+
- name: Run tests
33+
run: npm test -- --coverage
34+
35+
- name: Create production build
36+
env:
37+
CI: "true"
38+
VITE_API_URL: ${{ secrets.VITE_API_URL }}
39+
VITE_AUTH0_DOMAIN: ${{ secrets.VITE_AUTH0_DOMAIN }}
40+
VITE_AUTH0_CLIENT_ID: ${{ secrets.VITE_AUTH0_CLIENT_ID }}
41+
VITE_AUTH0_AUDIENCE: ${{ secrets.VITE_AUTH0_AUDIENCE }}
42+
VITE_DEV_MODE: "false"
43+
run: npm run build
44+
45+
- name: Configure AWS credentials
46+
uses: aws-actions/configure-aws-credentials@v4
47+
with:
48+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
49+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
50+
aws-region: ${{ secrets.AWS_REGION }}
51+
52+
- name: Deploy to S3
53+
run: |
54+
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET_NAME }}/ --delete
55+
56+
- name: Invalidate CloudFront cache
57+
run: |
58+
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
59+
60+
- name: Send deployment notification
61+
if: always()
62+
uses: slackapi/slack-github-action@v1
63+
with:
64+
payload: |
65+
{
66+
"text": "${{ job.status == 'success' && '✅ Frontend deployed successfully' || '❌ Frontend deployment failed' }}",
67+
"blocks": [
68+
{
69+
"type": "section",
70+
"text": {
71+
"type": "mrkdwn",
72+
"text": "${{ job.status == 'success' && '✅ Frontend deployed successfully to S3 and CloudFront' || '❌ Frontend deployment failed' }}"
73+
}
74+
},
75+
{
76+
"type": "section",
77+
"fields": [
78+
{
79+
"type": "mrkdwn",
80+
"text": "*S3 Bucket:* ${{ secrets.S3_BUCKET_NAME }}"
81+
},
82+
{
83+
"type": "mrkdwn",
84+
"text": "*CloudFront:* ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}"
85+
}
86+
]
87+
},
88+
{
89+
"type": "section",
90+
"text": {
91+
"type": "mrkdwn",
92+
"text": "*Commit:* <${{ github.event.repository.html_url }}/commit/${{ github.sha }}|${{ github.sha }}>"
93+
}
94+
},
95+
{
96+
"type": "section",
97+
"text": {
98+
"type": "mrkdwn",
99+
"text": "*Live URL:* https://${{ secrets.SITE_DOMAIN }}"
100+
}
101+
}
102+
]
103+
}
104+
env:
105+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
106+
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

DEPLOYMENT.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# Deployment Guide
2+
3+
This document provides detailed instructions for setting up and configuring the deployment pipeline for the Toban Contribution Viewer project.
4+
5+
## Infrastructure Setup
6+
7+
### Backend: AWS Elastic Beanstalk
8+
9+
1. **Create an Elastic Beanstalk Application:**
10+
```bash
11+
aws elasticbeanstalk create-application --application-name toban-contribution-viewer
12+
```
13+
14+
2. **Create an Elastic Beanstalk Environment:**
15+
```bash
16+
aws elasticbeanstalk create-environment \
17+
--application-name toban-contribution-viewer \
18+
--environment-name toban-contribution-viewer-prod \
19+
--solution-stack-name "64bit Amazon Linux 2023 v4.0.6 running Python 3.12" \
20+
--option-settings file://backend/eb-config.json
21+
```
22+
23+
3. **Configure Environment Variables:**
24+
Set the following environment variables in the Elastic Beanstalk environment:
25+
- `DATABASE_URL`: Your production PostgreSQL connection string
26+
- `SECRET_KEY`: A secure random string for production
27+
- `AUTH0_DOMAIN`: Your Auth0 domain
28+
- `AUTH0_CLIENT_ID`: Your Auth0 client ID
29+
- `AUTH0_CLIENT_SECRET`: Your Auth0 client secret
30+
- `AUTH0_AUDIENCE`: Your Auth0 API audience
31+
- `OPENAI_API_KEY`: Your OpenAI API key
32+
33+
4. **Set Up Database:**
34+
- Create an RDS PostgreSQL instance
35+
- Configure security groups to allow access from your Elastic Beanstalk environment
36+
- Create the initial database schema
37+
38+
### Frontend: AWS S3 and CloudFront
39+
40+
1. **Create an S3 Bucket:**
41+
```bash
42+
aws s3 mb s3://toban-contribution-viewer-frontend --region us-east-1
43+
```
44+
45+
2. **Configure the S3 Bucket for Static Website Hosting:**
46+
```bash
47+
aws s3 website s3://toban-contribution-viewer-frontend \
48+
--index-document index.html \
49+
--error-document index.html
50+
```
51+
52+
3. **Set Bucket Policy for Public Access:**
53+
Create a file named `bucket-policy.json` with the following content:
54+
```json
55+
{
56+
"Version": "2012-10-17",
57+
"Statement": [
58+
{
59+
"Sid": "PublicReadGetObject",
60+
"Effect": "Allow",
61+
"Principal": "*",
62+
"Action": "s3:GetObject",
63+
"Resource": "arn:aws:s3:::toban-contribution-viewer-frontend/*"
64+
}
65+
]
66+
}
67+
```
68+
Apply the policy:
69+
```bash
70+
aws s3api put-bucket-policy \
71+
--bucket toban-contribution-viewer-frontend \
72+
--policy file://bucket-policy.json
73+
```
74+
75+
4. **Create a CloudFront Distribution:**
76+
```bash
77+
aws cloudfront create-distribution \
78+
--origin-domain-name toban-contribution-viewer-frontend.s3.amazonaws.com \
79+
--default-root-object index.html
80+
```
81+
82+
5. **Configure Custom Domain (Optional):**
83+
- Create a certificate using AWS Certificate Manager
84+
- Add the domain to your CloudFront distribution
85+
- Configure DNS settings to point to your CloudFront distribution
86+
87+
## GitHub Actions Setup
88+
89+
### Creating Required Secrets
90+
91+
Add the following secrets to your GitHub repository:
92+
93+
1. AWS credentials:
94+
- `AWS_ACCESS_KEY_ID`: Your AWS access key
95+
- `AWS_SECRET_ACCESS_KEY`: Your AWS secret key
96+
- `AWS_REGION`: The AWS region (e.g., us-east-1)
97+
98+
2. Elastic Beanstalk configuration:
99+
- `EB_APPLICATION_NAME`: Your Elastic Beanstalk application name (e.g., toban-contribution-viewer)
100+
- `EB_ENVIRONMENT_NAME`: Your Elastic Beanstalk environment name (e.g., toban-contribution-viewer-prod)
101+
102+
3. S3 and CloudFront configuration:
103+
- `S3_BUCKET_NAME`: Your S3 bucket name (e.g., toban-contribution-viewer-frontend)
104+
- `CLOUDFRONT_DISTRIBUTION_ID`: Your CloudFront distribution ID
105+
- `SITE_DOMAIN`: Your site domain (e.g., app.yoursite.com)
106+
107+
4. Environment-specific variables:
108+
- All the required backend and frontend environment variables for production
109+
110+
5. Slack notifications (optional):
111+
- `SLACK_WEBHOOK_URL`: Your Slack webhook URL for deployment notifications
112+
113+
### Testing the Deployment
114+
115+
1. Push a change to the main branch to trigger the deployment workflow
116+
2. Monitor the GitHub Actions workflow run
117+
3. Verify the deployment was successful by accessing your application
118+
119+
## Deployment Environments
120+
121+
### Production
122+
123+
The production environment is automatically deployed when changes are pushed to the main branch. You can also manually trigger a deployment through the GitHub Actions interface.
124+
125+
### Staging (Optional)
126+
127+
To set up a staging environment:
128+
129+
1. Create additional Elastic Beanstalk environment and S3 bucket for staging
130+
2. Create a new GitHub workflow file specifically for staging deployment
131+
3. Configure the workflow to deploy to the staging environment when changes are pushed to a staging branch
132+
133+
## Rollback Procedures
134+
135+
### Backend Rollback
136+
137+
1. Open the Elastic Beanstalk console
138+
2. Navigate to your environment
139+
3. Select the "Application versions" tab
140+
4. Select the previous working version
141+
5. Click "Deploy" to roll back to that version
142+
143+
### Frontend Rollback
144+
145+
1. Navigate to your S3 bucket
146+
2. Restore a previous version using S3 versioning
147+
3. Invalidate the CloudFront cache to serve the restored version

0 commit comments

Comments
 (0)