Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Test

on:
push:
branches:
- '**'
pull_request:
branches:
- '**'

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run tests
run: ./gradlew test --no-daemon

13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# Package Files #
*.jar
!gradle/wrapper/gradle-wrapper.jar
*.war
*.nar
*.ear
Expand All @@ -22,3 +23,15 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

# Gradle
.gradle/
build/

# IDE
.idea/
*.iml

# OS
.DS_Store

85 changes: 83 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,83 @@
# gradle-python-plugin
Run python from a gradle task, including setting venv and setup env via requirements.txt
# Gradle Python Plugin

[![Test](https://github.com/jurgenei/gradle-python-plugin/actions/workflows/test.yml/badge.svg)](https://github.com/jurgenei/gradle-python-plugin/actions/workflows/test.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Run Python scripts from Gradle with isolated virtual environments and optional dependency installation.

## Highlights

- Creates and reuses a local `.venv` in your task working directory
- Installs `requirements.txt` only when file content changes (SHA-256 hash cache)
- Runs scripts with arguments and surfaces stdout/stderr in Gradle logs
- Provides a single task name: `PythonRunnerTask`

## Plugin Coordinates

- Plugin ID: `name.jurgenei.gradle.python`
- Java package: `name.jurgenei.gradle.python`
- Registered task: `PythonRunnerTask`

## Requirements

- JDK 17+ (tested with recent Gradle versions)
- Python 3 available on the build machine
- Gradle (or the provided wrapper)

## Quick Start

```groovy
plugins {
id 'name.jurgenei.gradle.python'
}

PythonRunnerTask {
script = file("scripts/run.py")
workDir = projectDir
requirements = file("requirements.txt") // optional
args = ["foo", "bar"] // optional
pythonExecutable = "/usr/bin/python3" // optional
}
```

Then run:

```bash
./gradlew PythonRunnerTask
```

## Task Properties

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `script` | `File` | Yes | Python script to execute. |
| `workDir` | `File` | No | Working directory and location for `.venv` (defaults to script parent, then project dir). |
| `requirements` | `File` | No | `requirements.txt` file to install; re-installs only when content hash changes. |
| `args` | `List<String>` | No | Positional arguments passed to the script. |
| `pythonExecutable` | `String` | No | Python interpreter used to create the virtual environment. |

## How Caching Works

When `requirements` is set, the plugin computes a SHA-256 hash of the file and stores it at `.venv/.requirements.hash`. If the hash is unchanged, dependency installation is skipped.

## Development

Run tests locally:

```bash
./gradlew test
```

## CI

GitHub Actions is configured to run tests on every push (any branch) and pull request.

## Contributing

1. Create a branch from `main`.
2. Run `./gradlew test` before opening a PR.
3. Submit a PR with a short change summary.

## License

This project is licensed under the terms of the `LICENSE` file.
31 changes: 31 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
plugins {
id 'java-gradle-plugin'
}

group = 'name.jurgenei.gradle'
version = '0.1.0'

repositories {
mavenCentral()
}

dependencies {
testImplementation gradleTestKit()
testImplementation 'org.junit.jupiter:junit-jupiter:5.12.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.12.2'
}

gradlePlugin {
plugins {
pythonRunner {
id = 'name.jurgenei.gradle.python'
implementationClass = 'name.jurgenei.gradle.python.PythonRunnerPlugin'
displayName = 'Python Runner Plugin'
description = 'Run Python scripts with per-project virtual environment and requirements caching.'
}
}
}

tasks.withType(Test).configureEach {
useJUnitPlatform()
}
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading