gradle support

This commit is contained in:
2025-05-20 10:53:22 +02:00
parent 84d55c546e
commit aa5349f704

View File

@@ -15,13 +15,13 @@ This YET only works with Maven!
""" """
import os import os
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import re import re
from pathlib import Path from pathlib import Path
import argparse import argparse
import glob import glob
import json
def parse_pom_xml(pom_path): def parse_pom_xml(pom_path):
@@ -107,19 +107,114 @@ def parse_pom_xml(pom_path):
"kotlin_version": kotlin_version, "kotlin_version": kotlin_version,
"source_dir": source_dir, "source_dir": source_dir,
"default_goal": default_goal, "default_goal": default_goal,
"pom_path": pom_path "pom_path": pom_path,
"build_system": "maven"
} }
except Exception as e: except Exception as e:
print(f"Error parsing {pom_path}: {e}") print(f"Error parsing {pom_path}: {e}")
return None return None
def generate_gitea_workflow(pom_infos): def parse_gradle_file(gradle_path):
""" """
Generate a Gitea workflow YAML file based on multiple POM information 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: if not pom_infos:
print("No valid POM files found") print("No valid Maven POM files found")
return None return None
# Get the highest Java version required # Get the highest Java version required
@@ -186,13 +281,15 @@ jobs:
if info["default_goal"]: if info["default_goal"]:
maven_command = info["default_goal"] maven_command = info["default_goal"]
relative_pom_path = info["pom_path"]
workflow_content += f""" workflow_content += f"""
- name: Build {info["name"]} ({info["artifact_id"]}) - name: Build {info["name"]} ({info["artifact_id"]})
run: | run: |
echo "Building {info["artifact_id"]}" echo "Building {info["artifact_id"]}"
echo "Current directory: $(pwd)" echo "Current directory: $(pwd)"
# Run Maven build directly using the POM file path # Run Maven build directly using the POM file path
mvn -B {maven_command} -f "$GITHUB_WORKSPACE/pom.xml" -Dmaven.compiler.failOnError=true mvn -B {maven_command} -f "{relative_pom_path}" -Dmaven.compiler.failOnError=true
""" """
# Add artifact upload step # Add artifact upload step
@@ -201,8 +298,108 @@ jobs:
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: {info["artifact_id"]} name: {info["artifact_id"]}
path: target/{info['artifact_id']}-*.jar path: |
if-no-files-found: error {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 return workflow_content
@@ -213,78 +410,176 @@ def find_pom_files(base_dir="."):
return glob.glob(f"{base_dir}/**/pom.xml", recursive=True) 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(): def main():
parser = argparse.ArgumentParser(description='Generate Gitea workflow for Maven/Kotlin projects') parser = argparse.ArgumentParser(description='Generate Gitea workflow for Maven/Gradle/Kotlin projects')
parser.add_argument('--dir', '-d', default='.', help='Base directory to search for pom.xml files') 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-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() args = parser.parse_args()
# Find project files
pom_files = [] pom_files = []
gradle_files = []
if args.specific_pom: if args.specific_pom:
pom_files = [args.specific_pom] pom_files = [args.specific_pom]
else: else:
pom_files = find_pom_files(args.dir) pom_files = find_pom_files(args.dir)
if not pom_files: if args.specific_gradle:
print(f"No pom.xml files found in {args.dir}") 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 return
print(f"Found {len(pom_files)} pom.xml files") print(f"Found {len(pom_files)} pom.xml files and {len(gradle_files)} Gradle files")
# Parse all POM files # Parse all project files
pom_infos = [] project_infos = []
# Parse Maven files
for pom_file in pom_files: for pom_file in pom_files:
info = parse_pom_xml(pom_file) info = parse_pom_xml(pom_file)
if info: if info:
pom_infos.append(info) project_infos.append(info)
if not pom_infos: # Parse Gradle files
print("No valid POM files could be parsed") 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 return
# Generate the workflow content # Count by build system
workflow_content = generate_gitea_workflow(pom_infos) 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")
if not workflow_content:
return
# Create the .gitea/workflows directory if it doesn't exist # Create the .gitea/workflows directory if it doesn't exist
workflow_dir = Path(".gitea/workflows") workflow_dir = Path(".gitea/workflows")
workflow_dir.mkdir(parents=True, exist_ok=True) workflow_dir.mkdir(parents=True, exist_ok=True)
# Write the workflow file # Generate and write workflow files for each build system
workflow_file = workflow_dir / "maven_build.yaml" if maven_count > 0:
with open(workflow_file, "w") as f: maven_infos = [p for p in project_infos if p["build_system"] == "maven"]
f.write(workflow_content) 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}")
print(f"Gitea workflow generated at: {workflow_file}") if gradle_count > 0:
print(f"This workflow will build {len(pom_infos)} Maven projects") 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 summary of detected projects
print("\nDetected projects:") print("\nDetected projects:")
for info in pom_infos: for info in project_infos:
kotlin_info = "with Kotlin" if info["is_kotlin"] else "Java only" kotlin_info = "with Kotlin" if info["is_kotlin"] else "Java only"
build_command = info["default_goal"] if info["default_goal"] else "clean package" if info["build_system"] == "maven":
print( build_command = info["default_goal"] if info["default_goal"] else "clean package"
f"- {info['name']} ({info['artifact_id']}): {kotlin_info}, Java {info['java_version']}, build: {build_command}") 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']}")
# Create a simple direct build script as fallback # Export as JSON if requested
with open("build.sh", "w") as f: if args.output_json:
f.write("""#!/bin/bash with open("project_info.json", "w") as f:
# Direct build script for Maven project json.dump(project_infos, f, indent=2)
print(f"Project information exported to project_info.json")
echo "Current directory: $(pwd)"
echo "Building project with Maven..."
# Run Maven build using the exact pom.xml location
mvn clean package -f "$(pwd)/pom.xml"
echo "Build complete. JAR file should be in target/ directory."
""")
# Make it executable
os.chmod("build.sh", 0o755)
print(f"Simple build script generated at: build.sh")
if __name__ == "__main__": if __name__ == "__main__":