about summary refs log tree commit diff
path: root/gradle/tasks.gradle
blob: 40fdac0b157cf8eb317a5823532facbbdc18c854 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
import org.apache.ivy.util.url.ApacheURLLister
import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.internal.logging.text.StyledTextOutputFactory

import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption

import static org.gradle.internal.logging.text.StyledTextOutput.Style

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
        maven {
            url "https://oss.sonatype.org/content/repositories/snapshots"
            mavenContent { snapshotsOnly() }
        }
    }
    
    dependencies {
        classpath "org.apache.ivy:ivy:${project.ivyVersion}"
        classpath "org.apereo.cas:cas-server-core-api-configuration-model:${project.'cas.version'}"
        classpath "org.apereo.cas:cas-server-core-configuration-metadata-repository:${project.'cas.version'}"
    }
}

apply plugin: "de.undercouch.download"

def tomcatDirectory = "${buildDir}/apache-tomcat-${tomcatVersion}"
project.ext."tomcatDirectory" = tomcatDirectory

def explodedDir = "${buildDir}/cas"
def explodedResourcesDir = "${buildDir}/cas-resources"

def resourcesJarName = "cas-server-webapp-resources"
def templateViewsJarName = "cas-server-support-thymeleaf"

task copyCasConfiguration(type: Copy, group: "CAS", description: "Copy the CAS configuration from this project to /etc/cas/config") {
    from "etc/cas/config"
    into new File('/etc/cas/config').absolutePath
    doFirst {
        new File('/etc/cas/config').mkdirs()
    }
}

task explodeWarOnly(type: Copy, group: "CAS", description: "Explodes the CAS web application archive") {
    dependsOn 'build'
    from zipTree("build/libs/${casWebApplicationBinaryName}")
    into explodedDir
    doLast {
        println "Exploded WAR into ${explodedDir}"
    }
}

task explodeWar(type: Copy, group: "CAS", description: "Explodes the CAS archive and resources jar from the CAS web application archive") {
    dependsOn explodeWarOnly
    from zipTree("${explodedDir}/WEB-INF/lib/${templateViewsJarName}-${casServerVersion}.jar")
    into explodedResourcesDir

    from zipTree("${explodedDir}/WEB-INF/lib/${resourcesJarName}-${casServerVersion}.jar")
    into explodedResourcesDir
    
    doLast {
        println "Exploded WAR resources into ${explodedResourcesDir}"
    }
}

task run(group: "build", description: "Run the CAS web application in embedded container mode") {
    dependsOn 'build'
    doLast {
        def casRunArgs = Arrays.asList("-server -noverify -Xmx2048M -XX:+TieredCompilation -XX:TieredStopAtLevel=1".split(" "))
        javaexec {
            main = "-jar"
            jvmArgs = casRunArgs
            args = ["build/libs/${casWebApplicationBinaryName}"]
            systemProperties = System.properties
            logger.info "Started ${commandLine}"
        }
    }
}

task setExecutable(group: "CAS", description: "Configure the project to run in executable mode") {
    doFirst {
        project.setProperty("executable", "true")
        logger.info "Configuring the project as executable"
    }
}

task executable(type: Exec, group: "CAS", description: "Run the CAS web application in standalone executable mode") {
    dependsOn setExecutable, 'build'
    doFirst {
        workingDir "."
        if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
            commandLine "chmod", "+x", bootWar.archivePath
        }
        logger.info "Running ${bootWar.archivePath}"
        commandLine bootWar.archivePath
    }
}

task debug(group: "CAS", description: "Debug the CAS web application in embedded mode on port 5005") {
    dependsOn 'build'
    doLast {
        logger.info "Debugging process is started in a suspended state, listening on port 5005."
        def casArgs = Arrays.asList("-Xmx2048M".split(" "))
        javaexec {
            main = "-jar"
            jvmArgs = casArgs
            debug = true
            args = ["build/libs/${casWebApplicationBinaryName}"]
            systemProperties = System.properties
            logger.info "Started ${commandLine}"
        }
    }
}

task downloadShell(group: "Shell", description: "Download CAS shell jar from snapshot or release maven repo") {
    doFirst {
        mkdir "${project.shellDir}"
    }
    doLast {
        def downloadFile
        if (isRunningCasServerSnapshot(casServerVersion)) {
            def snapshotDir = "https://oss.sonatype.org/content/repositories/snapshots/org/apereo/cas/cas-server-support-shell/${casServerVersion}/"
            def files = new ApacheURLLister().listFiles(new URL(snapshotDir))
            files = files.sort { it.path }
            files.each {
                if (it.path.endsWith(".jar")) {
                    downloadFile = it
                }
            }
        } else {
            downloadFile = "https://repo1.maven.org/maven2/org/apereo/cas/cas-server-support-shell/${casServerVersion}/cas-server-support-shell-${casServerVersion}.jar"
        }
        logger.info "Downloading file: ${downloadFile}"
        download {
            src downloadFile
            dest new File("${project.shellDir}", "cas-server-support-shell-${casServerVersion}.jar")
            overwrite false
        }
    }
}

task runShell(group: "Shell", description: "Run the CAS shell") {
    dependsOn downloadShell
    doLast {
        println "Run the following command to launch the shell:\n\tjava -jar ${project.shellDir}/cas-server-support-shell-${casServerVersion}.jar"
    }
}

task debugShell(group: "Shell", description: "Run the CAS shell with debug options, wait for debugger on port 5005") {
    dependsOn downloadShell
    doLast {
        println """
        Run the following command to launch the shell:\n\t
        java -Xrunjdwp:transport=dt_socket,address=5000,server=y,suspend=y -jar ${project.shellDir}/cas-server-support-shell-${casServerVersion}.jar
        """
    }
}

task showConfiguration(group: "CAS", description: "Show configurations for each dependency, etc") {
    doLast() {
        def cfg = project.hasProperty("configuration") ? project.property("configuration") : "compile"
        configurations.getByName(cfg).each { println it }
    }
}

task allDependenciesInsight(group: "build", type: DependencyInsightReportTask, description: "Produce insight information for all dependencies") {}

task allDependencies(group: "build", type: DependencyReportTask, description: "Display a graph of all project dependencies") {}

task casVersion(group: "CAS", description: "Display the current CAS version") {
    doFirst {
        def verbose = project.hasProperty("verbose") && Boolean.valueOf(project.getProperty("verbose"))
        if (verbose) {
            def out = services.get(StyledTextOutputFactory).create("CAS")
            println "******************************************************************"
            out.withStyle(Style.Info).println "Apereo CAS $casServerVersion"
            out.withStyle(Style.Description).println "Enterprise Single SignOn for all earthlings and beyond"
            out.withStyle(Style.SuccessHeader).println "- GitHub: "
            out.withStyle(Style.Success).println "https://github.com/apereo/cas"
            out.withStyle(Style.SuccessHeader).println "- Docs: "
            out.withStyle(Style.Success).println "https://apereo.github.io/cas"
            out.withStyle(Style.SuccessHeader).println "- Blog: "
            out.withStyle(Style.Success).println "https://apereo.github.io"
            println "******************************************************************"
        } else {
            println casServerVersion
        }
    }
}

task createKeystore(group: "CAS", description: "Create CAS keystore") {
    doFirst {
        mkdir "/etc/cas"

        def keystorePath = "/etc/cas/thekeystore"

        def dn = "CN=cas.example.org,OU=Example,OU=Org,C=US"
        if (project.hasProperty("certificateDn")) {
            dn = project.getProperty("certificateDn")
        }
        def subjectAltName = "dns:example.org,dns:localhost,ip:127.0.0.1"
        if (project.hasProperty("certificateSubAltName")) {
            subjectAltName = project.getProperty("certificateSubAltName")
        }
        // this will fail if thekeystore exists and has cert with cas alias already (so delete if you want to recreate)
        logger.info "Generating keystore for CAS with DN ${dn}"
        exec {
            workingDir "."
            commandLine "keytool", "-genkeypair", "-alias", "cas",
                    "-keyalg", "RSA",
                    "-keypass", "changeit", "-storepass", "changeit",
                    "-keystore", keystorePath,
                    "-dname", dn, "-ext", "SAN=${subjectAltName}"
        }
        logger.info "Exporting cert from keystore..."
        exec {
            workingDir "."
            commandLine "keytool", "-exportcert", "-alias", "cas",
                    "-storepass", "changeit", "-keystore", keystorePath,
                    "-file", "/etc/cas/cas.cer"
        }
        logger.info "Import /etc/cas/cas.cer into your Java truststore (JAVA_HOME/lib/security/cacerts)"
    }
}

task listTemplateViews(group: "CAS", description: "List all CAS views") {
    dependsOn explodeWar

    doFirst {
        fileTree(explodedResourcesDir).matching {
            include "**/*.html"
        }
        .collect { 
            return it.path.replace(explodedResourcesDir, "")
        }
        .toSorted()
        .each { println it }
    }
}

task exportConfigMetadata(group: "CAS", description: "Export collection of CAS properties") {
    doLast {
        def file = new File(project.rootDir, 'config-metadata.properties')
        file.withWriter('utf-8') { writer ->
            def metadataRepository = new org.apereo.cas.metadata.CasConfigurationMetadataRepository()
            def repository = metadataRepository.repository;
            repository.allGroups
                    .values()
                    .sort { o1, o2 -> o1.id <=> o2.id }
                    .each({ group ->
                        def groupProperties = group.properties
                        if (!groupProperties.isEmpty()) {
                            def groupId = group.id.equalsIgnoreCase("_ROOT_GROUP_") ? "" : group.id + "."

                            writer.writeLine("# Group ${group.id}");
                            writer.writeLine("# ====================")
                            groupProperties
                                    .values()
                                    .sort { o1, o2 -> o1.id <=> o2.id }
                                    .each({ property ->
                                        def description = property.shortDescription
                                        if (!property.shortDescription?.equalsIgnoreCase(property.description) && property.description != null) {
                                            description = property.description.replace('\n', '#')
                                        }
                                        writer.writeLine("# ${description}");
                                        writer.writeLine("# Type: ${property.type}");
                                        if (property.deprecated) {
                                            def deprecation = property.deprecation
                                            writer.writeLine("# This setting is deprecated with a severity level of ${deprecation.level}.")
                                            if (deprecation.shortReason != null) {
                                                writer.writeLine("# because ${deprecation.shortReason}")
                                            }
                                            if (deprecation.replacement != null) {
                                                writer.writeLine("# Replace with: ${deprecation.replacement}")
                                            }
                                        }
                                        property.hints.valueHints.each {
                                            if (it.value instanceof Object[]) {
                                                if (it.value[0].toString().contains("RequiresModule")) {
                                                    writer.writeLine("# Required module: org.apereo.cas:${it.description}")
                                                    writer.writeLine("# Automatically included/available: ${it.value[1]}")
                                                }
                                            }
                                            if (it.value.toString().contains("RequiredProperty")) {
                                                writer.writeLine("# Note: This setting is required!")
                                            }
                                        }
                                        writer.writeLine("${groupId}${property.name}=${property.defaultValue}")
                                        writer.writeLine("")
                                    });
                        }
                    });
        }
        println "Configuration metadata is available at ${file.absolutePath}"
    }
}

task getResource(group: "CAS", description: "Fetch a CAS resource and move it into the overlay") {
    dependsOn explodeWar

    doFirst {
        def resourceName = project.getProperty("resourceName")

        def results = fileTree(explodedResourcesDir).matching {
            include "**/${resourceName}.*"
            include "**/${resourceName}"
        }
        if (results.isEmpty()) {
            println "No resources could be found matching ${resourceName}"
            return
        }
        if (results.size() > 1) {
            println "Multiple resources found matching ${resourceName}:\n"
            results.each {
                println "\t-" + it.path.replace(explodedResourcesDir, "")
            }
            println "\nNarrow down your search criteria and try again."
            return
        }

        def fromFile = explodedResourcesDir
        def resourcesDir = "src/main/resources"
        mkdir resourcesDir

        def resourceFile = results[0].canonicalPath
        def toResourceFile = resourceFile.replace(fromFile, resourcesDir)

        def parent = file(toResourceFile).getParent()
        mkdir parent

        Files.copy(Paths.get(resourceFile), Paths.get(toResourceFile), StandardCopyOption.REPLACE_EXISTING)
        println "Copied file ${resourceFile} to ${toResourceFile}"
    }
}

def isRunningCasServerSnapshot(casServerVersion) {
    return "${casServerVersion}".contains("-SNAPSHOT")
}

task verifyRequiredJavaVersion {
    logger.info "Checking current Java version ${JavaVersion.current()} for required Java version ${project.targetCompatibility}"
    if (!JavaVersion.current().name.equalsIgnoreCase("${project.targetCompatibility}")) {
        throw new GradleException("Current Java version ${JavaVersion.current()} does not match required Java version ${project.targetCompatibility}")
    }
}