From fb7be3f51880e64810eff2cbfdb5f0d1a3da91c7 Mon Sep 17 00:00:00 2001 From: ahmedgamalyousef Date: Thu, 25 Sep 2025 16:11:56 +0300 Subject: [PATCH] Creating Project Files --- CICDpipeline.sh | 123 +++++++++++++ Dockerfile | 18 ++ app.py | 440 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 + 4 files changed, 583 insertions(+) create mode 100755 CICDpipeline.sh create mode 100644 Dockerfile create mode 100644 app.py create mode 100644 requirements.txt diff --git a/CICDpipeline.sh b/CICDpipeline.sh new file mode 100755 index 0000000..2497629 --- /dev/null +++ b/CICDpipeline.sh @@ -0,0 +1,123 @@ +#!/usr/bin/bash + +# Weather App Deployment Script +set -e # Exit on error + +echo "đŸŒ¤ī¸ Weather App Deployment" + +# Get project name from user +echo "📝 Enter your Ghaymah PROJECT name:" +read project_name + +# Validate project name +if [ -z "$project_name" ]; then + echo "❌ Project name cannot be empty!" + exit 1 +fi + +# Get app name from user +echo "📝 Enter your APP name (this will be the deployed application name):" +read app_name + +# Validate app name +if [ -z "$app_name" ]; then + echo "❌ App name cannot be empty!" + exit 1 +fi + +# Configuration +IMAGENAME="$app_name" # Use app name for image +DOCKER_USERNAME="ahmedgamalyousef" # Your Docker Hub username + +echo "🚀 Starting deployment..." +echo " Project: ${project_name}" +echo " App: ${app_name}" +echo " Image: ${IMAGENAME}" + +# Build Docker image +echo "đŸ—ī¸ Building ${IMAGENAME} image..." + +# Get current tag and increment +tag=$(docker image ls | grep ${IMAGENAME} | awk '{print $2}' | head -1) +if [ -z "${tag}" ]; then + new_tag=1 + echo "📌 No existing image found, starting with version 1" +else + echo "📌 Found existing tag: ${tag}" + docker rmi ${IMAGENAME}:${tag} || echo "âš ī¸ Could not remove old image, continuing..." + new_tag=$((tag + 1)) +fi + +# Build the image +echo "🔨 Building version ${new_tag}..." +docker build -t ${IMAGENAME}:${new_tag} . + +# Push to Docker Hub +echo "📤 Pushing to Docker Hub..." +docker tag ${IMAGENAME}:${new_tag} ${DOCKER_USERNAME}/${IMAGENAME}:${new_tag} +docker push ${DOCKER_USERNAME}/${IMAGENAME}:${new_tag} + +# Also tag as latest +docker tag ${IMAGENAME}:${new_tag} ${DOCKER_USERNAME}/${IMAGENAME}:latest +docker push ${DOCKER_USERNAME}/${IMAGENAME}:latest + +echo "✅ Image pushed: ${DOCKER_USERNAME}/${IMAGENAME}:${new_tag}" + +# Ghaymah deployment +if command -v gy &> /dev/null; then + echo "â˜ī¸ Setting up Ghaymah deployment..." + + # Create project with the project name + echo "🔧 Creating project: ${project_name}" + project_id=$(gy resource project create --set .name=${project_name} | awk '/ID:/ {print $NF}') + + if [ -z "$project_id" ]; then + echo "❌ Failed to get project ID" + exit 1 + fi + + echo "✅ Project ID: ${project_id}" + + # Create .ghaymah.json configuration using both names + cat > .ghaymah.json <Weather App

Weather App

' > templates/index.html + +EXPOSE 5000 + +CMD ["python", "app.py"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..6523029 --- /dev/null +++ b/app.py @@ -0,0 +1,440 @@ +from flask import Flask, request, jsonify, render_template_string +import requests +import os +from datetime import datetime + +app = Flask(__name__) + +# Get API key from environment variable (preferred) or use demo key +API_KEY = os.getenv('API_KEY', '6cf356ceb2ec0ff941855d4a43144e0e') +BASE_URL = 'https://api.openweathermap.org/data/2.5/weather' + +# HTML Template with embedded CSS and JavaScript - MUST BE DEFINED BEFORE ROUTES +HTML_TEMPLATE = """ + + + + + + Weather Forecast + + + +
+
+

Weather Forecast

+

Get real-time weather information for any city worldwide

+
+ +
+ + +
+ +
+ +
+
+

Fetching weather data...

+
+ +
+
+

-

+
+
-
+ Weather Icon +
+

-

+
+ +
+
+
Feels Like
+
-
+
+
+
Humidity
+
-
+
+
+
Pressure
+
-
+
+
+
Wind Speed
+
-
+
+
+
Visibility
+
-
+
+
+
Sunrise / Sunset
+
-
+
+
+
+ + +
+ + + + +""" + +def get_weather(city): + """Fetch weather data from OpenWeatherMap API""" + try: + url = f"{BASE_URL}?q={city}&appid={API_KEY}&units=metric" + response = requests.get(url, timeout=10) + response.raise_for_status() # Raises an HTTPError for bad responses + + data = response.json() + main = data['main'] + weather = data['weather'][0] + sys = data.get('sys', {}) + + return { + 'city': data['name'], + 'country': sys.get('country', ''), + 'temperature': round(main['temp']), + 'feels_like': round(main['feels_like']), + 'description': weather['description'].title(), + 'humidity': main['humidity'], + 'pressure': main['pressure'], + 'wind_speed': round(data['wind']['speed'], 1), + 'wind_deg': data['wind'].get('deg', 0), + 'visibility': data.get('visibility', 0), + 'icon': weather['icon'], + 'sunrise': datetime.fromtimestamp(sys.get('sunrise', 0)).strftime('%H:%M') if sys.get('sunrise') else 'N/A', + 'sunset': datetime.fromtimestamp(sys.get('sunset', 0)).strftime('%H:%M') if sys.get('sunset') else 'N/A', + 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S') + } + except requests.exceptions.RequestException as e: + print(f"API request failed: {e}") + return None + except (KeyError, ValueError) as e: + print(f"Error parsing weather data: {e}") + return None + +@app.route('/') +def home(): + return render_template_string(HTML_TEMPLATE) + +@app.route('/weather', methods=['GET', 'POST']) +def weather(): + if request.method == 'POST': + city = request.form.get('city') + else: + city = request.args.get('city') + + if not city: + return jsonify({'error': 'City parameter is required'}), 400 + + weather_data = get_weather(city) + if weather_data: + return jsonify(weather_data) + else: + return jsonify({'error': 'City not found or API request failed'}), 404 + +@app.route('/health') +def health(): + return jsonify({'status': 'healthy', 'timestamp': datetime.now().isoformat()}) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=False) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b509766 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask==2.3.3 +requests==2.31.0