Adding Gradle to a Hugo project

This post will show you how to add Gradle build capabilities to a Hugo project.

The preferred way of using Gradle is through a Gradle Wrapper. I assume you already have Gradle installed in your environment, but, if not, then follow the instructions here.

Starting the local Hugo server

Create a build.gradle file in the Hugo project folder, ie alongside the contents folder. This file will be read by Gradle, and defines the build tasks, attributes etc. we want to have in the project.

The first task we will write is going to enable us to start the local Hugo server. To do that we will create a new Gradle task of type Exec. Add the following to the empty build.gradle file.

task hugoLocal(type:Exec) {
    workingDir = file('.')
    commandLine 'hugo', 'server', '-D'
}

This task sets the working directory to the current directory, and then starts the Hugo server, setting it up to also serve draft pages in the content it is serving.

Building the site

The next Gradle task will allow us generate the Hugo site. By default, Hugo will create the site in the `public`folder of the project. First we create a variable to identify the output directory.

ext {
    hugoOutputDir = file("$projectDir/public")
}

and the add a task to allow us to call Hugo to do its work

task hugo(type: Exec) {
    workingDir = file('.')
    commandLine 'hugo'
}

When we run ./gradlew hugo the public folder is created and content is added.

> gw hugo

> Task :hugo
Building sites 
                   | EN
-------------------+-----
  Pages            |
 . . .

Total in 102 ms

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

Removing old contents

At this point we can create a Hugo site, have it served locally, and create the content we would like to deploy. However, Hugo does not empty the output directory before creating the content, so we risk having old files still in the output directory.

What we we need to do is add a task that will remove the Hugo output in public. We start by adding the base Gradle plugin to our build file

plugins {
    id 'base'
}

and add the location of the files Hugo is generating to the task’s outputs property

hugo.outputs.dir hugoOutputDir

At this point we have 2 choices. The base plugin will automatically create a clean<TaskName> task, so cleanHugo is already available. If you prefer to use the standard Gradle `clean`task, then we can configure it using

clean {
   delete hugo.outputs
}

Finally, we make sure that the hugo task depends on cleaning the previous output by extending the task definition

task hugo(type: Exec, dependsOn: 'cleanHugo') {
. . .
}

Complete build.gradle

The complete build.gradle file allows us to use Hugo locally and generate the site content we wish to publish

plugins {
    id 'base'
    id 'org.hidetake.ssh' version '2.10.1'
}

ext {
    hugoOutputDir = fileTree("$projectDir/public").getDir()
    sshKeyFile = '~/.ssh/id_sftp_port27'
}

remotes {
    one {
        host = 'sftp.port27.dk'
        user = 'port27.dk'
    }
}

ssh.settings {
    dryRun = project.hasProperty('dryRun')
    identity = new File(sshKeyFile)
    knownHosts = allowAnyHosts
//    fileTransfer = 'scp'
}

task hugo(type: Exec, dependsOn: 'cleanHugo') {
    workingDir = file('.')
    commandLine 'hugo'
}
hugo.outputs.dir hugoOutputDir

clean {
    delete hugo.outputs
}

task serve(type:Exec) {
    workingDir = file(projectDir)
    commandLine 'hugo', 'server', '-D'
}

task deploy() {
    doLast {
        ssh.run {
            session(remotes.one) {
                put from: "$projectDir/public/about", into: '.'
                put from: "$projectDir/public/categories", into: '.'
                put from: "$projectDir/public/css", into: '.'
                put from: "$projectDir/public/posts", into: '.'
                put from: "$projectDir/public/tags", into: '.'
                put from: "$projectDir/public/.htaccess", into: '.'
                put from: "$projectDir/public/404.html", into: '.'
                put from: "$projectDir/public/index.html", into: '.'
                put from: "$projectDir/public/index.xml", into: '.'
                put from: "$projectDir/public/sitemap.xml", into: '.'
//                new File("$projectDir/public").eachFileRecurse {
//                    println " ${it.absolutePath} -> ./${it.absolutePath - ~/.*\/public\//}"
//                    put from: it, into: "./${it.absolutePath - ~/.*\/public\//}"
//                }
            }
        }
    }
}