import streamlit as st import google.generativeai as genai import re import os import textwrap # Secret key and Google Gemini API configuration API_KEY = st.secrets["GOOGLE_API_KEY"] # Page configuration st.set_page_config(page_title="πŸš€βœ¨ Gemini2 CI/CD Gen Pro", page_icon="πŸš€βœ¨", layout="wide") # --- Helper Functions --- def send_message_to_model(message, model_name, temperature, top_p, top_k, max_tokens): """Sends a message to the AI model and returns the response.""" try: # AI model configurations GENERATION_CONFIG = { "temperature": temperature, "top_p": top_p, "top_k": top_k, "response_mime_type": "text/plain", "max_output_tokens": max_tokens, } MODEL = genai.GenerativeModel( model_name=model_name, generation_config=GENERATION_CONFIG, ) response = MODEL.start_chat(history=[]).send_message(message) return response.text except Exception as e: st.error(f"❌ Error communicating with the AI: {e}") return None def generate_cicd_pipeline(prompt_base, model_name, temperature, top_p, top_k, max_tokens, target_systems, custom_requirements, specific_details, deploy_details, docker_details, kubernetes_details, test_details): """Generates a CI/CD pipeline based on user settings.""" prompt = f""" You are an expert DevOps engineer specializing in CI/CD pipelines. Your task is to generate complete, secure, and efficient CI/CD pipeline configurations based on the following description: **Goal:** Create the most complete, detailed, and efficient CI/CD pipeline possible, considering all variables, edge cases, and potential scenarios. **Pipeline Description:** {prompt_base} **Target Systems:** {target_systems if target_systems else "None"} **Deployment Details:** {deploy_details if deploy_details else "None"} **Docker Details:** {docker_details if docker_details else "None"} **Kubernetes Details:** {kubernetes_details if kubernetes_details else "None"} **Test Details:** {test_details if test_details else "None"} **Custom Requirements:** {custom_requirements if custom_requirements else "None"} **Specific Details:** {specific_details if specific_details else "None"} **Response Format:** - Respond in Markdown format, including YAML code blocks for Argo CD, GitHub Actions, GitLab Runner, Jenkins, CircleCI, and a Docker Compose, with their original formatting and without line breaks. - The Argo CD code block must be delimited by ```yaml argocd and ```. - The GitHub Actions code block must be delimited by ```yaml githubactions and ```. - The GitLab Runner code block must be delimited by ```yaml gitlabrunner and ```. - The Jenkins code block must be delimited by ```yaml jenkins and ```. - The CircleCI code block must be delimited by ```yaml circleci and ```. - The Docker Compose code block must be delimited by ```yaml dockercompose and ```. - Do not include comments, explanations, or any other text outside the code block, unless the prompt requires. - The code must maintain its full vertical formatting, respecting indentation and line breaks. - The code must be realistic, using real-world examples, data, and situations. - Explore different approaches, techniques, and advanced practices, always prioritizing security and efficiency. - Use best practices for building images, running tests, and deploying applications. - Unless the user specifies otherwise, use the most current and secure versions of the tools and resources, using YAML and following best practices. - Use incremental reasoning to add improvements, expansions, and considerations to your code. - Use the history of the conversations so that the response is incremental. - If Docker is required, generate configurations to build Docker Images and push to Dockerhub. - If kubernetes is required, use Argo CD for deployments and create the necessary configurations, generating the application.yaml, and any other resources. - If any connection parameters are needed, use placeholders in the code with comments like 'PLEASE FILL THIS' indicating where the user should fill in. - Use comments to explain the configurations. - If the user does not specify target systems, generate for Argo CD, Github Actions and Gitlab Runner. **Important:** - Generate only one pipeline at a time. - Create the longest, most complete, and detailed code possible to cover a wide range of possibilities and scenarios. - Consider all the details of the request, expanding the response and improving the code. """ response = send_message_to_model(prompt, model_name, temperature, top_p, top_k, max_tokens) return response def parse_and_save_yaml(ai_code, short_title): """Parses the markdown and saves the YAML code.""" argocd_match = re.search(r'```yaml argocd\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) github_actions_match = re.search(r'```yaml githubactions\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) gitlab_runner_match = re.search(r'```yaml gitlabrunner\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) jenkins_match = re.search(r'```yaml jenkins\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) circleci_match = re.search(r'```yaml circleci\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) dockercompose_match = re.search(r'```yaml dockercompose\s*(.*?)\s*```', ai_code, re.DOTALL | re.IGNORECASE) argocd_code = argocd_match.group(1).strip() if argocd_match else None github_actions_code = github_actions_match.group(1).strip() if github_actions_match else None gitlab_runner_code = gitlab_runner_match.group(1).strip() if gitlab_runner_match else None jenkins_code = jenkins_match.group(1).strip() if jenkins_match else None circleci_code = circleci_match.group(1).strip() if circleci_match else None dockercompose_code = dockercompose_match.group(1).strip() if dockercompose_match else None base_file_name = f"cicd_pipeline_{short_title}" files = {} if argocd_code: files["argocd"] = {"name":f"{base_file_name}_argocd.yaml", "code":argocd_code} if github_actions_code: files["githubactions"] = {"name":f"{base_file_name}_githubactions.yaml", "code":github_actions_code} if gitlab_runner_code: files["gitlabrunner"] = {"name":f"{base_file_name}_gitlabrunner.yaml", "code":gitlab_runner_code} if jenkins_code: files["jenkins"] = {"name":f"{base_file_name}_jenkins.yaml", "code":jenkins_code} if circleci_code: files["circleci"] = {"name":f"{base_file_name}_circleci.yaml", "code":circleci_code} if dockercompose_code: files["dockercompose"] = {"name":f"{base_file_name}_dockercompose.yaml", "code":dockercompose_code} for key, value in files.items(): with open(value["name"], "w", encoding="utf-8") as f: f.write(value["code"]) return files def main(): st.title("πŸš€βœ¨ Gemini2 CI/CD Gen Pro by [Elias Andrade](https://github.com/chaos4455)") st.markdown("Generate advanced CI/CD pipelines with ease! πŸš€") st.markdown("---") # Layout in columns (sidebar and main area) col1, col2 = st.columns([1, 3]) with col1: st.header("βš™οΈ Settings") with st.expander("✨ AI Settings"): model_name = st.selectbox("πŸ€– AI Model", ["gemini-2.0-flash-exp", "gemini-1.5-flash"], index=0, help="Choose the AI model.") temperature = st.slider("🌑️ Temperature", min_value=0.1, max_value=1.0, value=0.7, step=0.1, help="Adjust the AI's creativity.") top_p = st.slider("Top P", min_value=0.1, max_value=1.0, value=0.8, step=0.1, help="Adjust the AI's sampling.") top_k = st.slider("Top K", min_value=1, max_value=100, value=40, step=1, help="Adjust the AI's number of candidate tokens.") max_tokens = st.number_input("πŸ“ Max Tokens", min_value=128, max_value=8192, value=8192, step=128, help="Adjust the maximum size of the response.") with st.expander("🧰 Pipeline Settings"): target_systems = st.multiselect("🎯 Target Systems", ["Argo CD", "GitHub Actions", "GitLab Runner", "Jenkins", "CircleCI", "Docker Compose", "Other"], default=["Argo CD", "GitHub Actions", "GitLab Runner"], help="Select the target systems for the pipeline.") deploy_details = st.text_area("πŸš€ Deployment Details", placeholder="Specify deployment details, e.g., Kubernetes manifests, Dockerfiles, etc.", help="Provide any details about how and where to deploy") docker_details = st.text_input("🐳 Docker Details", placeholder="Specify details like Docker registry, image names, etc.", help="Provide details about docker builds") kubernetes_details = st.text_input("☸️ Kubernetes Details", placeholder="Specify details like namespaces, deployments, etc.", help="Provide details about kubernetes deployments") test_details = st.text_input("πŸ§ͺ Test Details", placeholder="Specify test details or test commands", help="Provide any details about the tests to be executed") custom_requirements = st.text_input("βž• Custom Requirements:", placeholder="Specific steps or tools (e.g., terraform, ansible)", help="List any specific steps or tools.") specific_details = st.text_input("ℹ️ Specific Details", placeholder="Special options, edge cases", help="Add specific details for the pipeline generation.") with col2: # User's base prompt prompt_base = st.text_area("πŸ“ Describe the CI/CD Pipeline:", placeholder=textwrap.dedent(""" Describe your CI/CD pipeline in detail. Include: - Steps for building, testing, and deploying your application. - Specific tools to be used (e.g., Docker, Kubernetes, Argo CD, etc). - DockerHub details (user, password) or any other registry details. - Kubernetes cluster details. - Any custom parameters, configurations, or secrets you need. If those details are not included, the pipeline will be generated using defaults, and you must fill in the parameters. """), key="prompt_base", help="Provide a detailed description of your CI/CD pipeline.") if st.button("✨ Generate CI/CD Pipeline"): if not prompt_base: st.error("⚠️ Please enter a pipeline description.") return with st.spinner("⏳ Generating pipeline..."): ai_code = generate_cicd_pipeline( prompt_base, model_name, temperature, top_p, top_k, max_tokens, target_systems, custom_requirements, specific_details, deploy_details, docker_details, kubernetes_details, test_details ) if ai_code: st.markdown("### βœ… Generated Pipeline:") st.code(ai_code, language="text") short_title = prompt_base[:30].strip().replace(" ", "_").lower() files = parse_and_save_yaml(ai_code, short_title) for key, value in files.items(): st.download_button( label=f"⬇️ Download Pipeline (.{(key)})", data=value["code"], file_name=value["name"], mime="application/x-yaml", ) else: st.error("❌ Error generating the pipeline. Check the connection with the AI and try again.") if __name__ == "__main__": main()