A simple calculator web application for students to practice Python programming.
Students implement calculator methods in calculator.py and test them via a web interface.
- Open in VS Code
- Reopen in Container (VS Code will prompt you)
- Run the calculator:
python app.py
- Open browser:
http://localhost:5001
python main.py # CLI version
pytest # Run testsImplement these methods in calculator.py:
def add(self, a, b):
# TODO: Implement addition
result = a + b
self.history.append(f"{a} + {b} = {result}")
return result
def subtract(self, a, b):
# TODO: Implement subtraction
result = a - b
self.history.append(f"{a} - {b} = {result}")
return result
def multiply(self, a, b):
# TODO: Implement multiplication
result = a * b
self.history.append(f"{a} × {b} = {result}")
return result
def divide(self, a, b):
# TODO: Implement division
if b == 0:
raise ValueError("Cannot divide by zero")
result = a / b
self.history.append(f"{a} ÷ {b} = {result}")
return result- Unimplemented: Calculator shows "method not implemented yet!"
- Implement: Add code to calculator methods
- Test: Use web calculator to see results
- History: View calculation history
- Implement methods in
calculator.py(replacepasswith real code) - Test your work by running the web app or CLI
- Check tests with
pytest
calculator.py- Implement methods hereapp.py- Web server (already done)main.py- CLI version (already done)test_calculator.py- Tests (already done)
When all methods work, the calculator will be complete! 🎉
- GitLab CI/CD Setup: See GitLab CI/CD section above for quick setup
- Complete GitLab Guide: GITLAB_CI_CD_SETUP.md - Comprehensive educational guide with detailed explanations
- Testing Guide: TESTING_GUIDE.md - How to test your calculator
- Troubleshooting: TROUBLESHOOTING.md - Common issues and solutions
- CI/CD Overview: CI_CD_DOCUMENTATION.md - Detailed CI/CD architecture explanation
- Render Deployment: RENDER_DEPLOYMENT_SETUP.md - GitLab CI/CD automatic Render deployments with secrets
- GitHub Secrets: GITHUB_SECRETS_GUIDE.md - Setting up GitHub Actions secrets
- Docker Username: SETUP_DOCKER_USERNAME.md - Docker Hub setup
Build the image locally:
docker build -t calculator-app:local .Run the container:
docker run --rm -p 5001:5001 calculator-app:localFor local development with docker-compose:
# Start the application
docker-compose up
# Or run in detached mode
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the application
docker-compose downThe compose file includes:
- Application service on port 5001
- Health checks
- Volume mounts for live development (optional)
- Network configuration
This project includes CI/CD pipelines for multiple platforms.
GitHub Actions workflow (.github/workflows/ci-cd.yml) that:
- Runs tests on pushes and pull requests
- Publishes to Docker Hub on version tags (e.g.,
v1.2.3) - Publishes to Artifactory on version tags (optional)
For Docker Hub:
DOCKER_USERNAME– Secret – your Docker Hub usernameDOCKER_TOKEN– Secret – Docker Hub Personal Access Token (not password!)
Setup:
-
Add
DOCKER_USERNAMEas Secret:- GitHub → Settings → Secrets and variables → Actions → Secrets
- Click "New repository secret"
- Name:
DOCKER_USERNAME - Value: Your Docker Hub username (e.g.,
morbargig) - Click "Add secret"
-
Add
DOCKER_TOKENas Secret:- GitHub → Settings → Secrets and variables → Actions → Secrets
- Go to Docker Hub → Account Settings → Security
- Click "New Access Token", name it (e.g., "GitHub Actions")
- Set permissions: "Read, Write & Delete"
- Copy token and add as
DOCKER_TOKENsecret
For Artifactory (optional):
ARTIFACTORY_URL– Artifactory registry URL (e.g.,https://your-artifactory.com)ARTIFACTORY_REPO– Docker repository name in ArtifactoryARTIFACTORY_USERNAME– Artifactory usernameARTIFACTORY_PASSWORD– Artifactory password/API key
- Docker Hub:
${DOCKER_USERNAME}/calculator-app:latestand:vX.Y.Z - Artifactory:
${ARTIFACTORY_URL}/${ARTIFACTORY_REPO}/calculator-app:latestand:vX.Y.Z
This project includes a complete GitLab CI/CD setup with Docker Compose, including:
- GitLab CE (Community Edition) running locally
- GitLab Runner for executing CI/CD jobs
- Artifactory OSS for Docker registry
📖 For complete educational guide, see GITLAB_CI_CD_SETUP.md
Option 1: Automated Setup (Recommended)
make setupThis will start all services, wait for GitLab to initialize, display the root password, and register the GitLab Runner automatically.
Option 2: Manual Setup
-
Start Services:
make up
Wait 2-3 minutes for GitLab to fully initialize.
-
Get GitLab Root Password:
make bootstrap
Save the password shown (it's only displayed once).
-
Access GitLab:
- Open browser:
http://localhost:8080 - Login with username:
rootand the password from step 2 - Create a new project or push your code
- Open browser:
-
Register GitLab Runner:
Step 4a: Get Registration Token from GitLab UI
- In GitLab: Go to Settings → CI/CD → Runners
- Expand "Set up a specific runner manually"
- Copy the Registration Token (looks like
glrt-xxxxxxxxxxxxxxxxxxxx) - Note the GitLab URL shown (use
http://gitlabfor internal network)
Step 4b: Register the Runner
make register
When prompted:
- GitLab URL:
http://gitlab(orhttp://localhost:8080) - Registration Token: (paste the token from Step 4a)
Alternative: Manual Registration
docker exec -it gitlab-runner gitlab-runner register \ --url http://gitlab \ --registration-token YOUR_TOKEN_HERE \ --executor docker \ --docker-image docker:24 \ --description "docker-runner" \ --tag-list "docker,linux" \ --run-untagged="true"
-
Verify Runner Registration:
docker exec gitlab-runner gitlab-runner listYou should see your runner listed. Also verify in GitLab UI: Settings → CI/CD → Runners (should show a green circle).
The .gitlab-ci.yml defines three stages:
- test – Runs pytest on all branches and merge requests
- build – Builds Docker image and pushes to GitLab Container Registry
- push – Publishes to Artifactory (optional, manual trigger)
make help # Show all available commands
make up # Start all services
make down # Stop all services
make logs # View logs from all services
make status # Check service status
make bootstrap # Get GitLab root password
make register # Register GitLab Runner
make clean # Remove everything (⚠️ deletes all data)- GitLab: http://localhost:8080 (username:
root, password: runmake bootstrap) - Artifactory: http://localhost:8081 (username:
admin, password:password) - Artifactory Docker Registry: http://localhost:8082
Get Initial Auto-Generated Password:
# For first-time setup, get the auto-generated password
docker compose -f docker-compose.gitlab.yml exec gitlab cat /etc/gitlab/initial_root_password
# Or use the helper script
./get_gitlab_password.shReset Root Password (if needed):
# Reset the root password to a new password
docker compose -f docker-compose.gitlab.yml exec gitlab gitlab-rails runner "user = User.find_by(username: 'root'); user.password = 'YourNewPassword'; user.password_confirmation = 'YourNewPassword'; user.save!"Check GitLab Status:
# Check if GitLab is ready
./check_gitlab_status.sh
# Or manually check
curl -I http://localhost:8080Wait for GitLab to Initialize:
# Script that waits until GitLab is ready
./wait_for_gitlab.shImportant Notes:
- The initial root password is auto-generated and stored in
/etc/gitlab/initial_root_password - This password file is automatically deleted after 24 hours for security
- Change the password immediately after first login via the web UI
- If the initial password doesn't work (due to container restarts), use the reset command above
Fresh Installation (Start from Scratch):
# Stop and remove everything (including volumes)
docker compose -f docker-compose.gitlab.yml down -v
# Start fresh
docker compose -f docker-compose.gitlab.yml up -d
# Wait 3-5 minutes for initialization, then get the password
docker compose -f docker-compose.gitlab.yml exec gitlab cat /etc/gitlab/initial_root_passwordBuilt-in variables (automatically available):
CI_REGISTRY_USER,CI_REGISTRY_PASSWORD,CI_REGISTRY– GitLab Container RegistryCI_REGISTRY_IMAGE– Registry image path
Required: Configure Render Deployment Variables
For automatic Render deployments, set these in GitLab: Settings → CI/CD → Variables
| Variable | Value | Protected | Masked |
|---|---|---|---|
RENDER_SERVICE_ID |
srv-XXXXXXXXXXXXX |
✅ | ✅ |
RENDER_DEPLOY_KEY |
your-deploy-key |
✅ | ✅ |
📚 See RENDER_DEPLOYMENT_SETUP.md for detailed setup instructions
Optional: Configure Artifactory Variables
If you want to use Artifactory (optional), set these in GitLab: Settings → CI/CD → Variables
| Variable | Value | Protected | Masked |
|---|---|---|---|
ARTIFACTORY_USERNAME |
admin |
❌ | ❌ |
ARTIFACTORY_PASSWORD |
password |
❌ | ✅ |
ARTIFACTORY_URL |
http://artifactory:8082 |
❌ | ❌ |
ARTIFACTORY_REPO |
docker-local |
❌ | ❌ |
Note: First create the docker-local repository in Artifactory:
- Login to http://localhost:8081 (admin/password)
- Go to Repositories → Add Repositories → Docker
- Name:
docker-local, Type: Local, Save
- All branches/tags: Runs tests and builds image to GitLab Container Registry
- Artifactory push: Manual stage (trigger from GitLab UI → Pipelines)
- Render deployment: Automatic on main/master branches after tests pass
| Platform | Test | Build | Docker Hub | Artifactory | Render Deploy |
|---|---|---|---|---|---|
| GitHub Actions | ✅ All pushes/PRs | ✅ On tags | ✅ On tags | ✅ On tags (optional) | ✅ On main/tags (optional) |
| GitLab CI/CD | ✅ All branches/MRs | ✅ All branches | ❌ | ✅ Manual trigger | ✅ Auto on main/master |
Note: GitLab CI/CD runs locally via Docker Compose with GitLab CE, Runner, and Artifactory. See GITLAB_CI_CD_SETUP.md for detailed educational guide.
GitHub:
git tag v1.0.0
git push origin v1.0.0GitLab:
git tag v1.0.0
git push origin v1.0.0
# Then manually trigger Artifactory publish in GitLab UI if neededThis project includes configuration for deploying to Render.com, a cloud platform for hosting Docker containers and web services.
The render.yaml file configures automatic deployment to Render.com:
- Service Type: Web Service (Docker)
- Region: Oregon (configurable)
- Plan: Free tier (upgradeable)
- Health Check:
/healthendpoint - Auto Deploy: Enabled (deploys on push to main)
-
Connect Repository to Render:
- Go to Render Dashboard
- Click "New +" → "Web Service"
- Connect your GitHub/GitLab repository
- Select the repository and branch (e.g.,
main) - Render will detect
render.yamlautomatically
-
Configure Service:
- Render will use settings from
render.yaml - Set environment variables if needed (in Render dashboard)
- Review and create service
- Render will use settings from
-
Automatic Deploys:
- Every push to
mainbranch triggers automatic deployment - Build logs available in Render dashboard
- Every push to
Configure GitHub Actions to trigger Render deployments:
Required GitHub Secrets:
RENDER_API_KEY– Your Render API key (get from Render Dashboard → Account Settings → API Keys)RENDER_SERVICE_ID– Your Render service ID (found in service URL:https://dashboard.render.com/web/{SERVICE_ID})
Deployment Behavior:
- Triggers on push to
main/masterbranches - Triggers on version tags (
v*.*.*) - Skips automatically if credentials not set
If you've published images to Docker Hub, you can deploy from Docker Hub:
- In Render Dashboard, create new "Web Service"
- Choose "Docker" environment
- Enter Docker image:
{DOCKER_USERNAME}/calculator-app:latest - Configure as needed
Set these in Render Dashboard → Environment:
FLASK_ENV=production(already in render.yaml)PYTHONUNBUFFERED=1(already in render.yaml)- Add custom variables as needed
After deployment, your service will be available at:
- Free tier:
https://calculator-app.onrender.com(or custom domain) - Custom domains can be configured in Render dashboard
The service uses:
- Build Command: (empty, handled by Docker)
- Start Command:
python app.py - Health Check:
GET /health
- View logs: Render Dashboard → Service → Logs
- Metrics: CPU, Memory, Request count
- Alerts: Configure in Render Dashboard
- Services sleep after 15 minutes of inactivity (wake on first request)
- Limited build minutes per month
- Single instance
Upgrade for:
- Always-on services (no sleep)
- Multiple instances
- More build minutes
- Custom domains with SSL