Implemented serve task for development mode

This commit is contained in:
Sebastian Sdorra
2020-12-22 09:26:20 +01:00
committed by René Pfeuffer
parent 6430c811e2
commit fa7edc55b2
11 changed files with 410 additions and 21 deletions

View File

@@ -29,8 +29,11 @@ plugins {
}
dependencies {
implementation(gradleApi())
implementation gradleApi()
implementation 'com.google.guava:guava:30.0-jre'
implementation 'com.github.node-gradle:gradle-node-plugin:2.2.4'
implementation 'org.eclipse.jetty:jetty-server:9.4.35.v20201120'
implementation 'org.eclipse.jetty:jetty-webapp:9.4.35.v20201120'
}
gradlePlugin {
@@ -40,6 +43,10 @@ gradlePlugin {
id = 'org.scm-manager.core-plugins'
implementationClass = 'com.cloudogu.scm.CorePluginsGradlePlugin'
}
serve {
id = 'org.scm-manager.serve'
implementationClass = 'com.cloudogu.scm.ServePlugin'
}
}
}
@@ -47,4 +54,7 @@ repositories {
maven {
url "https://packages.scm-manager.org/repository/public/"
}
maven {
url 'https://plugins.gradle.org/m2/'
}
}

View File

@@ -0,0 +1,140 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the 'Software'), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.cloudogu.scm
import com.google.common.base.Strings
import groovy.json.JsonSlurper
import org.eclipse.jetty.server.HttpConfiguration
import org.eclipse.jetty.server.HttpConnectionFactory
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.util.component.AbstractLifeCycle
import org.eclipse.jetty.util.component.LifeCycle
import org.eclipse.jetty.webapp.WebAppContext
import java.awt.Desktop
public class ScmServer {
def configuration
private Server server
private ScmServer(def configuration) {
this.configuration = configuration
}
void start() throws Exception {
info('start scm-server at port %s', configuration.port)
System.setProperty('scm.home', configuration.home)
if (configuration.disableCorePlugins) {
info('disable core plugin extraction')
System.setProperty('sonia.scm.boot.disable-core-plugin-extraction', 'true')
}
if (!Strings.isNullOrEmpty(configuration.loggingConfiguration)) {
System.setProperty('logback.configurationFile', configuration.loggingConfiguration);
}
info('set stage %s', configuration.stage)
System.setProperty('scm.stage', configuration.stage)
server = new Server()
server.addConnector(createServerConnector(server))
server.setHandler(createScmContext())
server.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
@Override
void lifeCycleStarted(LifeCycle event) {
String endpoint = String.format('http://localhost:%d%s', configuration.port, configuration.contextPath)
System.out.println()
System.out.println('==> scm-server started successfully and is accessible at:')
System.out.append('==> ').println(endpoint)
System.out.println()
if (configuration.openBrowser) {
openBrowser(endpoint)
}
}
})
server.start()
}
private static void openBrowser(String endpoint) {
try {
Desktop desktop = Desktop.getDesktop()
desktop.browse(URI.create(endpoint))
} catch (IOException | URISyntaxException ex) {
warn('could not open browser', ex)
}
}
private static void info(String message, Object... args) {
log('INFO', message, args)
}
private static void warn(String message, Exception exception) {
log('WARN', message)
exception.printStackTrace(System.out)
}
private static void log(String level, String template, Object... args) {
System.out.println("[${level}] " + String.format(template, args))
}
private WebAppContext createScmContext() {
WebAppContext warContext = new WebAppContext()
warContext.setContextPath(configuration.contextPath)
warContext.setExtractWAR(true)
warContext.setWar(configuration.warFile)
return warContext
}
private ServerConnector createServerConnector(Server server) throws MalformedURLException {
ServerConnector connector = new ServerConnector(server)
HttpConfiguration cfg = new HttpConfiguration()
cfg.setRequestHeaderSize(configuration.headerSize)
cfg.setResponseHeaderSize(configuration.headerSize)
connector.setConnectionFactories([new HttpConnectionFactory(cfg)])
connector.setPort(configuration.port)
return connector
}
static void main(String[] args) {
String configurationPath = args[0]
JsonSlurper slurper = new JsonSlurper()
def configuration = slurper.parse(new File(configurationPath))
ScmServer server = new ScmServer(configuration)
server.start()
}
}

View File

@@ -0,0 +1,49 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.cloudogu.scm
import org.gradle.api.Plugin
import org.gradle.api.Project
import com.moowork.gradle.node.NodeExtension
class ServePlugin implements Plugin<Project> {
void apply(Project project) {
project.plugins.apply("com.github.node-gradle.node")
def nodeExt = NodeExtension.get(project)
nodeExt.setDownload(true)
nodeExt.setVersion('14.15.1')
nodeExt.setYarnVersion('1.22.5')
nodeExt.setNodeModulesDir( project.rootProject.projectDir )
project.tasks.register('write-server-config', WriteServerConfigTask)
project.tasks.register("serve", ServeTask) {
dependsOn 'write-server-config', 'yarnSetup'
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the 'Software'), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.cloudogu.scm
import com.moowork.gradle.node.yarn.YarnTask
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.TaskAction
class ServeTask extends DefaultTask {
@TaskAction
void exec() {
List<Closure<Void>> actions = new ArrayList<>();
actions.add(createBackend())
actions.add(createFrontend())
def threads = start(actions)
wait(threads)
}
private static void wait(List<Thread> threads) {
for (Thread thread : threads) {
thread.join()
}
}
private static List<Thread> start(List<Closure<Void>> actions) {
return actions.collect({ action ->
Thread thread = new Thread(action)
thread.start()
return thread
})
}
private Closure<Void> createBackend() {
def backend = project.tasks.create('boot-backend', JavaExec) {
main ScmServer.class.name
args(new File(project.buildDir, 'server/config.json').toString())
environment 'NODE_ENV', 'development'
classpath project.buildscript.configurations.classpath
}
return {
backend.exec()
}
}
private Closure<Void> createFrontend() {
def frontend = project.tasks.create('boot-frontend', YarnTask) {
args = ['run', 'serve']
environment = [
'NODE_ENV': 'development'
]
}
return {
frontend.exec()
}
}
}

View File

@@ -0,0 +1,92 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the 'Software'), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.cloudogu.scm
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import groovy.xml.MarkupBuilder
import java.io.BufferedWriter
import org.gradle.api.tasks.Input
import com.google.common.hash.Hashing
import com.google.common.io.Files
import groovy.json.JsonOutput
class WriteServerConfigTask extends DefaultTask {
@Input
public String getHome() {
if (project.hasProperty('home')) {
return project.getProperty('home')
}
return new File(project.buildDir, 'scm-home').toString()
}
@Input
public int getPort() {
if (project.hasProperty('port')) {
return Integer.parseInt(project.getProperty('port'))
}
return 8081
}
@InputFile
public File getWarFile() {
return new File(project.buildDir, 'libs/scm-webapp-dev.war')
}
@OutputFile
public File getServerConfig() {
return new File(project.buildDir, 'server/config.json')
}
@TaskAction
void execute() {
File serverConfig = getServerConfig()
serverConfig.getParentFile().mkdirs()
serverConfig.text = JsonOutput.toJson([
home: getHome(),
port: getPort(),
contextPath: '/scm',
stage: 'DEVELOPMENT',
headerSize: 16384,
openBrowser: true,
warFile: getWarFile().toString()
])
}
}

View File

@@ -26,6 +26,10 @@ plugins {
id 'java-platform'
}
task('serve') {
dependsOn ':scm-ui:yarn_install', ':scm-webapp:serve'
}
dependencies {
constraints {
// lombok

View File

@@ -23,14 +23,14 @@
*/
plugins {
id 'com.github.node-gradle.node' version '2.2.4'
id 'com.github.node-gradle.node' version '2.2.4'
}
node {
download = true
version = '14.15.1'
yarnVersion = '1.22.5'
nodeModulesDir = file('${project.rootProject.projectDir}')
nodeModulesDir = file(project.rootProject.projectDir)
}
// TODO define inputs and outputs
@@ -50,7 +50,7 @@ task typecheck(type: YarnTask) {
doLast {
File directory = new File(project.buildDir, 'tmp/typecheck')
directory.mkdirs()
File marker = new File(directory, "marker")
File marker = new File(directory, 'marker')
marker.createNewFile()
}
}

View File

@@ -25,6 +25,7 @@
plugins {
id 'war'
id 'org.scm-manager.core-plugins'
id 'org.scm-manager.serve'
id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.1.6'
}
@@ -144,6 +145,18 @@ war {
from project.configurations.assets
dependsOn 'copy-core-plugins'
}
// war without assets for development and livereload
task 'dev-war' (type: War) {
archiveName 'scm-webapp-dev.war'
from 'build/war'
dependsOn 'copy-core-plugins'
}
serve {
dependsOn 'dev-war'
}
/**
WTF???

View File

@@ -24,22 +24,19 @@
rootProject.name = 'scm'
def includePlugin(String name) {
include ":${name}"
project(":${name}").projectDir = new File("scm-plugins/${name}")
}
includeBuild 'build-plugins'
include 'scm-annotations'
include 'scm-annotation-processor'
include 'scm-core'
include 'scm-test'
include 'scm-ui'
include 'scm-plugins:scm-git-plugin'
include 'scm-plugins:scm-hg-plugin'
include 'scm-plugins:scm-svn-plugin'
include 'scm-plugins:scm-legacy-plugin'
include 'scm-plugins:scm-integration-test-plugin'
include 'scm-dao-xml'
include 'scm-webapp'
include 'scm-server'
include('scm-annotations')
include('scm-annotation-processor')
include('scm-core')
include('scm-test')
// include('scm-ui')
includePlugin('scm-git-plugin')
includePlugin('scm-hg-plugin')
includePlugin('scm-svn-plugin')
includePlugin('scm-legacy-plugin')
includePlugin('scm-integration-test-plugin')
include('scm-dao-xml')
include('scm-webapp')
include('scm-server')
includeBuild '../gradle-smp-plugin'