Simple, lightweight, and modern Gradle plugin for uploading files via SFTP protocol
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Usage Examples
- Task Properties
- Best Practices
- Troubleshooting
- Contributing
- License
- π Secure File Transfer - Upload files securely using SFTP protocol
- π― Simple Configuration - Easy-to-use DSL for quick setup
- π Lightweight - Minimal dependencies, fast execution
- π§ Gradle Integration - Seamlessly integrates with Gradle build lifecycle
- π¦ Flexible - Support for custom ports, paths, and file locations
- π‘οΈ Error Handling - Comprehensive error messages and exception handling
- π Logging - Built-in logging for upload status and debugging
- Gradle: 8.0 or higher
- Java: 11 or higher
- SFTP Server: Accessible SFTP server with valid credentials
Add the plugin to your build.gradle.kts:
plugins {
id("ovh.neziw.sftp") version "1.0.0"
}If you're using the older plugin application method:
buildscript {
repositories {
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
dependencies {
classpath("ovh.neziw.sftp:gradle-sftp-plugin:1.0.0")
}
}
apply(plugin = "ovh.neziw.sftp")plugins {
id("ovh.neziw.sftp") version "1.0.0"
}
tasks.register<SftpTask>("upload") {
host.set("sftp.example.com")
port.set(22)
username.set("myusername")
password.set("mypassword")
localFile.set(file("build/libs/my-app.jar"))
remotePath.set("/home/user/applications/my-app.jar")
}Run the task:
./gradlew uploadThe plugin automatically registers a task named sftpUpload with default configuration. You can also create custom tasks:
tasks.register<SftpTask>("uploadToProduction") {
// Configuration here
}
tasks.register<SftpTask>("uploadToStaging") {
// Configuration here
}tasks.register<SftpTask>("uploadJar") {
host.set("deploy.example.com")
port.set(22)
username.set("deployer")
password.set(project.findProperty("sftp.password") as String? ?: "")
val jarName = "my-application-${project.version}.jar"
localFile.set(file("build/libs/${jarName}"))
remotePath.set("/opt/applications/${jarName}")
}tasks.register<SftpTask>("uploadRelease") {
host.set("releases.example.com")
port.set(2222) // Custom port
username.set("releaser")
password.set(System.getenv("SFTP_PASSWORD") ?: "")
val artifactName = "${project.name}-${project.version}.jar"
localFile.set(file("build/libs/${artifactName}"))
remotePath.set("/releases/${project.version}/${artifactName}")
// Make upload depend on build
dependsOn("build")
}tasks.register<SftpTask>("uploadDistributions") {
host.set("dist.example.com")
port.set(22)
username.set("distuser")
password.set(project.findProperty("sftp.password") as String? ?: "")
// Upload main JAR
localFile.set(file("build/libs/${project.name}-${project.version}.jar"))
remotePath.set("/distributions/jar/${project.name}-${project.version}.jar")
}
tasks.register<SftpTask>("uploadSources") {
host.set("dist.example.com")
port.set(22)
username.set("distuser")
password.set(project.findProperty("sftp.password") as String? ?: "")
// Upload sources JAR
localFile.set(file("build/libs/${project.name}-${project.version}-sources.jar"))
remotePath.set("/distributions/sources/${project.name}-${project.version}-sources.jar")
}
// Create a task that uploads both
tasks.register("uploadAll") {
dependsOn("uploadDistributions", "uploadSources")
}val environment = project.findProperty("env") as String? ?: "development"
tasks.register<SftpTask>("uploadToEnvironment") {
when (environment) {
"production" -> {
host.set("prod-sftp.example.com")
username.set("prod-user")
remotePath.set("/prod/applications/")
}
"staging" -> {
host.set("staging-sftp.example.com")
username.set("staging-user")
remotePath.set("/staging/applications/")
}
else -> {
host.set("dev-sftp.example.com")
username.set("dev-user")
remotePath.set("/dev/applications/")
}
}
port.set(22)
password.set(project.findProperty("sftp.password") as String? ?: "")
localFile.set(file("build/libs/${project.name}-${project.version}.jar"))
}tasks.register<SftpTask>("deploy") {
host.set("deploy.example.com")
port.set(22)
username.set("deployer")
password.set(System.getenv("DEPLOY_PASSWORD") ?: "")
val artifactName = "${project.name}-${project.version}.jar"
localFile.set(file("build/libs/${artifactName}"))
remotePath.set("/var/applications/${artifactName}")
// Ensure build completes before deployment
dependsOn("build")
// Only run if build was successful
mustRunAfter("build")
}| Property | Type | Required | Description | Default |
|---|---|---|---|---|
host |
String |
β Yes | SFTP server hostname or IP address | "your-host.com" |
port |
Integer |
β Yes | SFTP server port number | 22 |
username |
String |
β Yes | SFTP server username | "your-username" |
password |
String |
β Yes | SFTP server password | "your-password" |
localFile |
File |
β Yes | Local file to upload | file("build/libs/your-library.jar") |
remotePath |
String |
β Yes | Remote path where file will be uploaded | "/path/to/remote/your-library.jar" |
Never hardcode passwords in your build files. Use Gradle properties or environment variables:
// In gradle.properties (not committed to VCS)
// sftp.password=your-secure-password
// In build.gradle.kts
password.set(project.findProperty("sftp.password") as String? ?: "")Or use environment variables:
password.set(System.getenv("SFTP_PASSWORD") ?: "")Create a gradle.properties file (and add it to .gitignore):
sftp.host=your-sftp-server.com
sftp.port=22
sftp.username=your-username
sftp.password=your-passwordThen reference it in your build:
tasks.register<SftpTask>("upload") {
host.set(project.findProperty("sftp.host") as String? ?: "")
port.set((project.findProperty("sftp.port") as String?)?.toInt() ?: 22)
username.set(project.findProperty("sftp.username") as String? ?: "")
password.set(project.findProperty("sftp.password") as String? ?: "")
// ...
}Always ensure required tasks complete before upload:
tasks.register<SftpTask>("upload") {
dependsOn("build")
// ...
}The plugin includes built-in error handling, but you can add custom error handling:
tasks.register<SftpTask>("upload") {
// ... configuration ...
doLast {
if (!localFile.get().exists()) {
throw GradleException("Local file does not exist: ${localFile.get().absolutePath}")
}
}
}Problem: Cannot connect to SFTP server
Solutions:
- Verify host and port are correct
- Check network connectivity:
telnet <host> <port> - Ensure firewall allows SFTP connections
- Verify credentials are correct
Problem: Authentication failed
Solutions:
- Double-check username and password
- Ensure the user has write permissions on the remote path
- Verify the user account is active
Problem: Local file does not exist
Solutions:
- Verify the file path is correct
- Ensure the build task has completed successfully
- Check file permissions
Problem: Permission denied on remote path
Solutions:
- Verify the user has write permissions
- Check if the remote directory exists
- Ensure the remote path is accessible
tasks.register<SftpTask>("customUploadTask") {
// Your configuration
}tasks.register<SftpTask>("conditionalUpload") {
onlyIf {
project.hasProperty("upload.enabled") &&
project.property("upload.enabled") == "true"
}
// Configuration
}Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with JSch for SFTP functionality
- Inspired by the need for simple SFTP uploads in Gradle builds
If you encounter any issues or have questions, please open an issue on the GitHub repository.
Made with β€οΈ by neziw