Skip to main content
Glama
gradle.ts11.8 kB
/** * @fileoverview Android Gradle Tools * * Provides Gradle build system integration for Android projects, including building, * testing, dependency management, and task execution. Supports both Gradle wrapper * (gradlew) and global Gradle installations. * * @module tools/android/gradle * @category Development Workflow * @see {@link https://developer.android.com/studio/build|Android Gradle Build System} */ import { z } from 'zod'; import { ProcessExecutor } from '../../utils/process.js'; import path from 'path'; import fs from 'fs/promises'; const processExecutor = new ProcessExecutor(); /** * Zod validation schema for android_gradle_build tool. * * @type {z.ZodObject} */ const AndroidGradleBuildSchema = z.object({ projectPath: z.string().min(1), task: z.string().default('assembleDebug'), options: z.object({ clean: z.boolean().default(false), parallel: z.boolean().default(true), daemon: z.boolean().default(true), stacktrace: z.boolean().default(false), info: z.boolean().default(false), debug: z.boolean().default(false), }).optional(), }); const AndroidGradleTasksSchema = z.object({ projectPath: z.string().min(1), taskGroup: z.string().optional(), }); const AndroidGradleCleanSchema = z.object({ projectPath: z.string().min(1), }); const AndroidGradleDependenciesSchema = z.object({ projectPath: z.string().min(1), configuration: z.string().optional(), }); // Helper function to find gradlew async function findGradleWrapper(projectPath: string): Promise<string> { const gradlewPath = process.platform === 'win32' ? 'gradlew.bat' : 'gradlew'; const fullPath = path.join(projectPath, gradlewPath); try { await fs.access(fullPath); return fullPath; } catch { // Fall back to system gradle if gradlew not found return 'gradle'; } } // Helper function to validate Android project async function validateAndroidProject(projectPath: string): Promise<void> { const buildGradlePath = path.join(projectPath, 'build.gradle'); const buildGradleKtsPath = path.join(projectPath, 'build.gradle.kts'); try { await fs.access(buildGradlePath); } catch { try { await fs.access(buildGradleKtsPath); } catch { throw new Error(`No build.gradle or build.gradle.kts found in ${projectPath}`); } } } export function createAndroidGradleTools(): Map<string, any> { const tools = new Map(); tools.set('android_gradle_build', { name: 'android_gradle_build', description: 'Build Android project using Gradle wrapper or system Gradle', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to Android project directory' }, task: { type: 'string', description: 'Gradle task to execute', default: 'assembleDebug' }, options: { type: 'object', properties: { clean: { type: 'boolean', description: 'Run clean before build', default: false }, parallel: { type: 'boolean', description: 'Enable parallel execution', default: true }, daemon: { type: 'boolean', description: 'Use Gradle daemon', default: true }, stacktrace: { type: 'boolean', description: 'Show full stacktrace on errors', default: false }, info: { type: 'boolean', description: 'Set log level to INFO', default: false }, debug: { type: 'boolean', description: 'Set log level to DEBUG', default: false } } } }, required: ['projectPath'] }, handler: async (args: any) => { const parsed = AndroidGradleBuildSchema.parse(args); try { await validateAndroidProject(parsed.projectPath); const gradlePath = await findGradleWrapper(parsed.projectPath); const gradleArgs = []; // Add options if (parsed.options?.clean) { gradleArgs.push('clean'); } gradleArgs.push(parsed.task); if (parsed.options?.parallel) { gradleArgs.push('--parallel'); } if (!parsed.options?.daemon) { gradleArgs.push('--no-daemon'); } if (parsed.options?.stacktrace) { gradleArgs.push('--stacktrace'); } if (parsed.options?.info) { gradleArgs.push('--info'); } if (parsed.options?.debug) { gradleArgs.push('--debug'); } const result = await processExecutor.execute(gradlePath, gradleArgs, { cwd: parsed.projectPath, timeout: 300000, // 5 minutes }); if (result.exitCode === 0) { return { success: true, data: { task: parsed.task, output: result.stdout, projectPath: parsed.projectPath, buildTime: result.duration } }; } else { return { success: false, error: { code: 'GRADLE_BUILD_FAILED', message: 'Gradle build failed', details: { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode } } }; } } catch (error: any) { return { success: false, error: { code: 'GRADLE_BUILD_ERROR', message: error.message, details: error } }; } } }); tools.set('android_gradle_tasks', { name: 'android_gradle_tasks', description: 'List available Gradle tasks for Android project', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to Android project directory' }, taskGroup: { type: 'string', description: 'Filter tasks by group (build, verification, etc.)' } }, required: ['projectPath'] }, handler: async (args: any) => { const parsed = AndroidGradleTasksSchema.parse(args); try { await validateAndroidProject(parsed.projectPath); const gradlePath = await findGradleWrapper(parsed.projectPath); const gradleArgs = ['tasks']; if (parsed.taskGroup) { gradleArgs.push('--group', parsed.taskGroup); } else { gradleArgs.push('--all'); } const result = await processExecutor.execute(gradlePath, gradleArgs, { cwd: parsed.projectPath, timeout: 60000, }); if (result.exitCode === 0) { // Parse tasks from output const tasks = result.stdout .split('\n') .filter(line => line.includes(' - ')) .map((line: string) => { const [task, description] = line.split(' - '); return { name: task?.trim() || '', description: description?.trim() || '' }; }); return { success: true, data: { tasks, totalTasks: tasks.length, projectPath: parsed.projectPath, taskGroup: parsed.taskGroup } }; } else { return { success: false, error: { code: 'GRADLE_TASKS_FAILED', message: 'Failed to list Gradle tasks', details: result.stderr } }; } } catch (error: any) { return { success: false, error: { code: 'GRADLE_TASKS_ERROR', message: error.message, details: error } }; } } }); tools.set('android_gradle_clean', { name: 'android_gradle_clean', description: 'Clean Android project build artifacts', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to Android project directory' } }, required: ['projectPath'] }, handler: async (args: any) => { const parsed = AndroidGradleCleanSchema.parse(args); try { await validateAndroidProject(parsed.projectPath); const gradlePath = await findGradleWrapper(parsed.projectPath); const result = await processExecutor.execute(gradlePath, ['clean'], { cwd: parsed.projectPath, timeout: 120000, // 2 minutes }); if (result.exitCode === 0) { return { success: true, data: { message: 'Project cleaned successfully', output: result.stdout, projectPath: parsed.projectPath } }; } else { return { success: false, error: { code: 'GRADLE_CLEAN_FAILED', message: 'Gradle clean failed', details: result.stderr } }; } } catch (error: any) { return { success: false, error: { code: 'GRADLE_CLEAN_ERROR', message: error.message, details: error } }; } } }); tools.set('android_gradle_dependencies', { name: 'android_gradle_dependencies', description: 'Show Android project dependencies tree', inputSchema: { type: 'object', properties: { projectPath: { type: 'string', description: 'Path to Android project directory' }, configuration: { type: 'string', description: 'Dependency configuration (implementation, testImplementation, etc.)' } }, required: ['projectPath'] }, handler: async (args: any) => { const parsed = AndroidGradleDependenciesSchema.parse(args); try { await validateAndroidProject(parsed.projectPath); const gradlePath = await findGradleWrapper(parsed.projectPath); const gradleArgs = ['dependencies']; if (parsed.configuration) { gradleArgs.push('--configuration', parsed.configuration); } const result = await processExecutor.execute(gradlePath, gradleArgs, { cwd: parsed.projectPath, timeout: 120000, }); if (result.exitCode === 0) { return { success: true, data: { dependenciesTree: result.stdout, configuration: parsed.configuration, projectPath: parsed.projectPath } }; } else { return { success: false, error: { code: 'GRADLE_DEPENDENCIES_FAILED', message: 'Failed to get dependencies', details: result.stderr } }; } } catch (error: any) { return { success: false, error: { code: 'GRADLE_DEPENDENCIES_ERROR', message: error.message, details: error } }; } } }); return tools; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cristianoaredes/mcp-mobile-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server