#!/usr/bin/env python3 """ ``` POMMER.PY ``` !:: THIS IS PROPRIETARY SOFTWARE DO NOT DISTRIBUTE TO OUTSIDERS ::! This Python File is distributed with every Kotlin / Java Plugin Repository! If you find this to be confusing to use look at the Documentation in "rattatwinko/pommer" Run this Script with Python 3.11 ; 3.9 This works with Gradle and Maven ; other Branch is for reliablitiy ; this one is for "Support" with larger *commercial* Builds !:: Maven Building with the Master Branch ( this Version ) is broken! It will not build into a .JAR ; Building using the "nogradle" branch, will work ::! """ import os import xml.etree.ElementTree as ET import re from pathlib import Path import argparse import glob import json def parse_pom_xml(pom_path): """ Parse a pom.xml file and extract relevant information """ try: print(f"Parsing POM file: {pom_path}") # Register the default namespace ET.register_namespace('', "http://maven.apache.org/POM/4.0.0") # Parse the XML file tree = ET.parse(pom_path) root = tree.getroot() # Define namespace for easier XPath queries ns = {'mvn': "http://maven.apache.org/POM/4.0.0"} # Extract project info artifact_id = root.find('./mvn:artifactId', ns).text group_id = root.find('./mvn:groupId', ns).text if root.find('./mvn:groupId', ns) is not None else "unknown" version = root.find('./mvn:version', ns).text if root.find('./mvn:version', ns) is not None else "unknown" name = root.find('./mvn:name', ns).text if root.find('./mvn:name', ns) is not None else artifact_id # Extract Java version java_version_elem = root.find('./mvn:properties/mvn:java.version', ns) java_version = java_version_elem.text if java_version_elem is not None else "17" # Default to Java 17 if not specified # Extract packaging type (default to jar if not specified) packaging = root.find('./mvn:packaging', ns) packaging = packaging.text if packaging is not None else "jar" # Check if Kotlin is used kotlin_version_elem = root.find('./mvn:properties/mvn:kotlin.version', ns) kotlin_version = kotlin_version_elem.text if kotlin_version_elem is not None else None # Check for Kotlin plugin or dependency kotlin_plugin = None kotlin_dep = None # Check for Kotlin plugin plugins = root.findall('.//mvn:plugin', ns) for plugin in plugins: plugin_group = plugin.find('./mvn:groupId', ns) if plugin_group is not None and plugin_group.text == 'org.jetbrains.kotlin': kotlin_plugin = plugin break # Check for Kotlin dependency deps = root.findall('.//mvn:dependency', ns) for dep in deps: dep_group = dep.find('./mvn:groupId', ns) dep_artifact = dep.find('./mvn:artifactId', ns) if (dep_group is not None and dep_group.text == 'org.jetbrains.kotlin' and dep_artifact is not None and 'kotlin-stdlib' in dep_artifact.text): kotlin_dep = dep break # Determine if this is a Kotlin project is_kotlin = kotlin_version is not None or kotlin_plugin is not None or kotlin_dep is not None # Check for source directories source_dir = None source_dirs = root.findall('.//mvn:sourceDirectory', ns) if source_dirs: source_dir = source_dirs[0].text # Check for default goal (to use the same command as IntelliJ) default_goal = None default_goal_elem = root.find('./mvn:build/mvn:defaultGoal', ns) if default_goal_elem is not None: default_goal = default_goal_elem.text return { "artifact_id": artifact_id, "group_id": group_id, "version": version, "name": name, "java_version": java_version, "packaging": packaging, "is_kotlin": is_kotlin, "kotlin_version": kotlin_version, "source_dir": source_dir, "default_goal": default_goal, "pom_path": pom_path, "build_system": "maven" } except Exception as e: print(f"Error parsing {pom_path}: {e}") return None def parse_gradle_file(gradle_path): """ Parse a build.gradle or build.gradle.kts file and extract relevant information """ try: print(f"Parsing Gradle file: {gradle_path}") # Read the file content with open(gradle_path, 'r') as f: content = f.read() # Determine if it's a Kotlin DSL file is_kotlin_dsl = gradle_path.endswith('.kts') # Extract group, version and project name group_match = re.search(r'group\s*=\s*[\'"]([^\'"]+)[\'"]', content) group_id = group_match.group(1) if group_match else "unknown" version_match = re.search(r'version\s*=\s*[\'"]([^\'"]+)[\'"]', content) version = version_match.group(1) if version_match else "unknown" # Check settings.gradle for project name settings_path = os.path.join(os.path.dirname(gradle_path), "settings.gradle") settings_path_kts = os.path.join(os.path.dirname(gradle_path), "settings.gradle.kts") artifact_id = "unknown" name = "unknown" if os.path.exists(settings_path): with open(settings_path, 'r') as f: settings_content = f.read() root_project_match = re.search(r'rootProject\.name\s*=\s*[\'"]([^\'"]+)[\'"]', settings_content) if root_project_match: artifact_id = root_project_match.group(1) name = artifact_id elif os.path.exists(settings_path_kts): with open(settings_path_kts, 'r') as f: settings_content = f.read() root_project_match = re.search(r'rootProject\.name\s*=\s*[\'"]([^\'"]+)[\'"]', settings_content) if root_project_match: artifact_id = root_project_match.group(1) name = artifact_id # If no name found in settings.gradle, use directory name if artifact_id == "unknown": artifact_id = os.path.basename(os.path.dirname(gradle_path)) name = artifact_id # Check for Java version java_version = "17" # Default to Java 17 java_version_match = re.search(r'sourceCompatibility\s*=\s*[\'"]*JavaVersion\.VERSION_(\d+)[\'"]*', content) if java_version_match: java_version = java_version_match.group(1) else: # Alternative pattern: sourceCompatibility = '11' alt_java_match = re.search(r'sourceCompatibility\s*=\s*[\'"](\d+)[\'"]', content) if alt_java_match: java_version = alt_java_match.group(1) else: # Look for toolchain configuration toolchain_match = re.search(r'toolchain\s*{[^}]*languageVersion\s*=\s*JavaLanguageVersion\s*\.\s*of\s*\(\s*(\d+)\s*\)', content, re.DOTALL) if toolchain_match: java_version = toolchain_match.group(1) # Check if Kotlin is used kotlin_plugin_match = re.search(r'(id\s*\(\s*[\'"]kotlin[\'"])|(id\s*[\'"]org\.jetbrains\.kotlin)', content) kotlin_version_match = re.search(r'kotlin\s*version\s*[\'"]([^\'"]+)[\'"]', content) is_kotlin = bool(kotlin_plugin_match) or bool(kotlin_version_match) or is_kotlin_dsl kotlin_version = kotlin_version_match.group(1) if kotlin_version_match else None # Check for application plugin is_application = bool(re.search(r'id\s*\(\s*[\'"]application[\'"]', content)) return { "artifact_id": artifact_id, "group_id": group_id, "version": version, "name": name, "java_version": java_version, "packaging": "jar" if not is_application else "application", "is_kotlin": is_kotlin, "kotlin_version": kotlin_version, "source_dir": None, # Gradle uses conventional source dirs "default_goal": None, # Gradle doesn't have default goals like Maven "gradle_path": gradle_path, "is_kotlin_dsl": is_kotlin_dsl, "build_system": "gradle" } except Exception as e: print(f"Error parsing {gradle_path}: {e}") return None def generate_maven_workflow(pom_infos): """ Generate a Gitea workflow YAML file for Maven projects """ if not pom_infos: print("No valid Maven POM files found") return None # Get the highest Java version required java_version = max([info["java_version"] for info in pom_infos]) # Check if any project uses Kotlin uses_kotlin = any(info["is_kotlin"] for info in pom_infos) # Kotlin version (if any) kotlin_version = None for info in pom_infos: if info["kotlin_version"]: kotlin_version = info["kotlin_version"] break # Construct the workflow content workflow_content = f"""name: Maven Build on: push: branches: [ main, master, dev ] pull_request: branches: [ main, master ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up JDK {java_version} uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '{java_version}' cache: 'maven' - name: Install Maven run: | if ! command -v mvn &> /dev/null; then echo "Maven not found, installing..." sudo apt-get update sudo apt-get install -y maven fi mvn --version - name: Debug Info run: | echo "Current workspace directory: $GITHUB_WORKSPACE" echo "Current directory: $(pwd)" echo "Project structure:" find . -type f -name "*.kt" | sort find . -type f -name "pom.xml" echo "Maven version: $(mvn --version)" """ # Add individual build steps for each POM for i, info in enumerate(pom_infos): # Determine the Maven command to use (same as the default goal if specified) maven_command = "clean package" if info["default_goal"]: maven_command = info["default_goal"] relative_pom_path = info["pom_path"] workflow_content += f""" - name: Build {info["name"]} ({info["artifact_id"]}) run: | echo "Building {info["artifact_id"]}" echo "Current directory: $(pwd)" # Run Maven build directly using the POM file path mvn -B {maven_command} -f "{relative_pom_path}" -Dmaven.compiler.failOnError=true """ # Add artifact upload step workflow_content += f""" - name: Upload {info["artifact_id"]} artifact uses: actions/upload-artifact@v3 with: name: {info["artifact_id"]} path: | {os.path.dirname(relative_pom_path)}/target/{info['artifact_id']}-*.jar {os.path.dirname(relative_pom_path)}/target/*.jar if-no-files-found: warn """ return workflow_content def generate_gradle_workflow(gradle_infos): """ Generate a Gitea workflow YAML file for Gradle projects """ if not gradle_infos: print("No valid Gradle files found") return None # Get the highest Java version required java_version = max([info["java_version"] for info in gradle_infos]) # Check if any project uses Kotlin uses_kotlin = any(info["is_kotlin"] for info in gradle_infos) # Kotlin version (if any) kotlin_version = None for info in gradle_infos: if info["kotlin_version"]: kotlin_version = info["kotlin_version"] break # Construct the workflow content workflow_content = f"""name: Gradle Build on: push: branches: [ main, master, dev ] pull_request: branches: [ main, master ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up JDK {java_version} uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '{java_version}' cache: 'gradle' - name: Grant execute permission for gradlew run: | find . -name gradlew -type f -exec chmod +x {{}} \; - name: Debug Info run: | echo "Current workspace directory: $GITHUB_WORKSPACE" echo "Current directory: $(pwd)" echo "Project structure:" find . -type f -name "*.kt" | sort find . -type f -name "build.gradle*" if [ -f ./gradlew ]; then ./gradlew --version else echo "No wrapper found, will use system gradle" gradle --version fi """ # Add individual build steps for each Gradle project for i, info in enumerate(gradle_infos): project_dir = os.path.dirname(info["gradle_path"]) has_wrapper = os.path.exists(os.path.join(project_dir, "gradlew")) gradle_command = f"{os.path.join(project_dir, 'gradlew')}" if has_wrapper else "gradle" workflow_content += f""" - name: Build {info["name"]} ({info["artifact_id"]}) working-directory: {project_dir} run: | echo "Building {info["artifact_id"]}" echo "Current directory: $(pwd)" # Run Gradle build {"./gradlew" if has_wrapper else "gradle"} build """ # Add artifact upload step workflow_content += f""" - name: Upload {info["artifact_id"]} artifact uses: actions/upload-artifact@v3 with: name: {info["artifact_id"]} path: | {project_dir}/build/libs/*.jar {project_dir}/app/build/libs/*.jar {project_dir}/build/distributions/*.zip {project_dir}/app/build/distributions/*.zip if-no-files-found: warn """ return workflow_content def find_pom_files(base_dir="."): """Find all pom.xml files in the given directory and subdirectories""" return glob.glob(f"{base_dir}/**/pom.xml", recursive=True) def find_gradle_files(base_dir="."): """Find all build.gradle and build.gradle.kts files in the given directory and subdirectories""" gradle_files = glob.glob(f"{base_dir}/**/build.gradle", recursive=True) kotlin_gradle_files = glob.glob(f"{base_dir}/**/build.gradle.kts", recursive=True) return gradle_files + kotlin_gradle_files def generate_build_script(project_infos): """Generate a universal build script for either Maven or Gradle projects""" maven_projects = [p for p in project_infos if p["build_system"] == "maven"] gradle_projects = [p for p in project_infos if p["build_system"] == "gradle"] script = """#!/bin/bash # Universal build script for Maven and Gradle projects echo "Current directory: $(pwd)" """ if maven_projects: script += """ # Check if Maven is installed if ! command -v mvn &> /dev/null; then echo "Maven not found, installing..." sudo apt-get update sudo apt-get install -y maven fi echo "Maven version: $(mvn --version)" """ for project in maven_projects: script += f""" echo "Building Maven project: {project['name']}" mvn clean package -f "{project['pom_path']}" """ if gradle_projects: script += """ # Check for Gradle or Gradle Wrapper """ for project in gradle_projects: project_dir = os.path.dirname(project["gradle_path"]) has_wrapper = os.path.exists(os.path.join(project_dir, "gradlew")) if has_wrapper: script += f""" echo "Building Gradle project using wrapper: {project['name']}" cd "{project_dir}" chmod +x ./gradlew ./gradlew build cd - > /dev/null """ else: script += f""" echo "Building Gradle project using system Gradle: {project['name']}" # Install Gradle if not available if ! command -v gradle &> /dev/null; then echo "Gradle not found, installing..." sudo apt-get update sudo apt-get install -y gradle fi cd "{project_dir}" gradle build cd - > /dev/null """ script += """ echo "Build complete. Build artifacts should be in their respective target/ or build/libs/ directories." """ return script def main(): parser = argparse.ArgumentParser(description='Generate Gitea workflow for Maven/Gradle/Kotlin projects') parser.add_argument('--dir', '-d', default='.', help='Base directory to search for project files') parser.add_argument('--specific-pom', '-p', help='Path to a specific pom.xml file to process') parser.add_argument('--specific-gradle', '-g', help='Path to a specific build.gradle file to process') parser.add_argument('--output-json', '-j', action='store_true', help='Output project info as JSON as well') args = parser.parse_args() # Find project files pom_files = [] gradle_files = [] if args.specific_pom: pom_files = [args.specific_pom] else: pom_files = find_pom_files(args.dir) if args.specific_gradle: gradle_files = [args.specific_gradle] else: gradle_files = find_gradle_files(args.dir) if not pom_files and not gradle_files: print(f"No pom.xml or build.gradle files found in {args.dir}") return print(f"Found {len(pom_files)} pom.xml files and {len(gradle_files)} Gradle files") # Parse all project files project_infos = [] # Parse Maven files for pom_file in pom_files: info = parse_pom_xml(pom_file) if info: project_infos.append(info) # Parse Gradle files for gradle_file in gradle_files: info = parse_gradle_file(gradle_file) if info: project_infos.append(info) if not project_infos: print("No valid project files could be parsed") return # Count by build system maven_count = sum(1 for p in project_infos if p["build_system"] == "maven") gradle_count = sum(1 for p in project_infos if p["build_system"] == "gradle") # Create the .gitea/workflows directory if it doesn't exist workflow_dir = Path(".gitea/workflows") workflow_dir.mkdir(parents=True, exist_ok=True) # Generate and write workflow files for each build system if maven_count > 0: maven_infos = [p for p in project_infos if p["build_system"] == "maven"] maven_workflow = generate_maven_workflow(maven_infos) if maven_workflow: maven_workflow_file = workflow_dir / "maven_build.yaml" with open(maven_workflow_file, "w") as f: f.write(maven_workflow) print(f"Gitea Maven workflow generated at: {maven_workflow_file}") if gradle_count > 0: gradle_infos = [p for p in project_infos if p["build_system"] == "gradle"] gradle_workflow = generate_gradle_workflow(gradle_infos) if gradle_workflow: gradle_workflow_file = workflow_dir / "gradle_build.yaml" with open(gradle_workflow_file, "w") as f: f.write(gradle_workflow) print(f"Gitea Gradle workflow generated at: {gradle_workflow_file}") # Generate a universal build script build_script = generate_build_script(project_infos) with open("build.sh", "w") as f: f.write(build_script) os.chmod("build.sh", 0o755) print(f"Universal build script generated at: build.sh") # Print summary of detected projects print("\nDetected projects:") # What the actuall fuck is going on here? Whoever reads this may God be with you! for info in project_infos: kotlin_info = "with Kotlin" if info["is_kotlin"] else "Java only" if info["build_system"] == "maven": build_command = info["default_goal"] if info["default_goal"] else "clean package" print(f"- {info['name']} ({info['artifact_id']}): Maven, {kotlin_info}, Java {info['java_version']}, build: {build_command}") else: dsl_info = "Kotlin DSL" if info.get("is_kotlin_dsl") else "Groovy DSL" print(f"- {info['name']} ({info['artifact_id']}): Gradle ({dsl_info}), {kotlin_info}, Java {info['java_version']}") # Export as JSON if requested if args.output_json: with open("project_info.json", "w") as f: json.dump(project_infos, f, indent=2) print(f"Project information exported to project_info.json") # Run script! if __name__ == "__main__": main()