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 xml.etree.ElementTree as ET
import re
from pathlib import Path
import argparse
import glob
import json
def parse_pom_xml(pom_path):
@@ -107,19 +107,114 @@ def parse_pom_xml(pom_path):
"kotlin_version": kotlin_version,
"source_dir": source_dir,
"default_goal": default_goal,
"pom_path": pom_path
"pom_path": pom_path,
"build_system": "maven"
}
except Exception as e:
print(f"Error parsing {pom_path}: {e}")
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:
print("No valid POM files found")
print("No valid Maven POM files found")
return None
# Get the highest Java version required
@@ -186,13 +281,15 @@ jobs:
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 "$GITHUB_WORKSPACE/pom.xml" -Dmaven.compiler.failOnError=true
mvn -B {maven_command} -f "{relative_pom_path}" -Dmaven.compiler.failOnError=true
"""
# Add artifact upload step
@@ -201,8 +298,108 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: {info["artifact_id"]}
path: target/{info['artifact_id']}-*.jar
if-no-files-found: error
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
@@ -213,78 +410,176 @@ def find_pom_files(base_dir="."):
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/Kotlin projects')
parser.add_argument('--dir', '-d', default='.', help='Base directory to search for pom.xml files')
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 not pom_files:
print(f"No pom.xml files found in {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")
print(f"Found {len(pom_files)} pom.xml files and {len(gradle_files)} Gradle files")
# Parse all POM files
pom_infos = []
# Parse all project files
project_infos = []
# Parse Maven files
for pom_file in pom_files:
info = parse_pom_xml(pom_file)
if info:
pom_infos.append(info)
project_infos.append(info)
if not pom_infos:
print("No valid POM files could be parsed")
# 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
# Generate the workflow content
workflow_content = generate_gitea_workflow(pom_infos)
if not workflow_content:
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)
# Write the workflow file
workflow_file = workflow_dir / "maven_build.yaml"
with open(workflow_file, "w") as f:
f.write(workflow_content)
# 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}")
print(f"Gitea workflow generated at: {workflow_file}")
print(f"This workflow will build {len(pom_infos)} Maven projects")
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:")
for info in pom_infos:
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']}): {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
with open("build.sh", "w") as f:
f.write("""#!/bin/bash
# Direct build script for Maven project
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")
# 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")
if __name__ == "__main__":