Migrate scm-it module to gradle

This commit is contained in:
Sebastian Sdorra
2020-12-23 16:33:35 +01:00
committed by René Pfeuffer
parent 36118c2e2a
commit 3a4a5a9d10
15 changed files with 466 additions and 32 deletions

View File

@@ -51,6 +51,10 @@ gradlePlugin {
id = 'org.scm-manager.serve' id = 'org.scm-manager.serve'
implementationClass = 'com.cloudogu.scm.ServePlugin' implementationClass = 'com.cloudogu.scm.ServePlugin'
} }
integrationTest {
id = 'org.scm-manager.integration-tests'
implementationClass = 'com.cloudogu.scm.IntegrationTestPlugin'
}
} }
} }

View File

@@ -0,0 +1,52 @@
/*
* 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
class IntegrationTestPlugin implements Plugin<Project> {
void apply(Project project) {
def extension = project.extensions.create("scmServer", ScmServerExtension, project)
project.tasks.register('write-server-config', WriteServerConfigTask) {
it.extension = extension
}
project.tasks.register("startScmServer", ServeTask) {
it.extension = extension
it.waitForCompletion = false
it.frontend = false
dependsOn 'write-server-config'
}
project.tasks.register("stopScmServer", StopScmServer) {
it.extension = extension
}
}
}

View File

@@ -33,6 +33,9 @@ import org.eclipse.jetty.server.ServerConnector
import org.eclipse.jetty.util.component.AbstractLifeCycle import org.eclipse.jetty.util.component.AbstractLifeCycle
import org.eclipse.jetty.util.component.LifeCycle import org.eclipse.jetty.util.component.LifeCycle
import org.eclipse.jetty.webapp.WebAppContext import org.eclipse.jetty.webapp.WebAppContext
import org.eclipse.jetty.server.Handler
import org.eclipse.jetty.server.handler.HandlerList
import org.eclipse.jetty.server.handler.ShutdownHandler
import java.awt.Desktop import java.awt.Desktop
@@ -61,12 +64,20 @@ public class ScmServer {
info('set stage %s', configuration.stage) info('set stage %s', configuration.stage)
System.setProperty('scm.stage', configuration.stage) System.setProperty('scm.stage', configuration.stage)
if (!Strings.isNullOrEmpty(configuration.livereloadUrl)) {
info('set livereload url', configuration.livereloadUrl) info('set livereload url', configuration.livereloadUrl)
System.setProperty('sonia.scm.ui.proxy', configuration.livereloadUrl) System.setProperty('sonia.scm.ui.proxy', configuration.livereloadUrl)
}
server = new Server() server = new Server()
server.addConnector(createServerConnector(server)) server.addConnector(createServerConnector(server))
server.setHandler(createScmContext())
HandlerList handlerList = new HandlerList()
handlerList.setHandlers([
createScmContext(),
createShutdownHandler()
] as Handler[])
server.setHandler(handlerList)
server.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() { server.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
@Override @Override
void lifeCycleStarted(LifeCycle event) { void lifeCycleStarted(LifeCycle event) {
@@ -119,6 +130,10 @@ public class ScmServer {
return warContext return warContext
} }
private ShutdownHandler createShutdownHandler() {
return new ShutdownHandler("_shutdown_", true, false)
}
private ServerConnector createServerConnector(Server server) throws MalformedURLException { private ServerConnector createServerConnector(Server server) throws MalformedURLException {
ServerConnector connector = new ServerConnector(server) ServerConnector connector = new ServerConnector(server)
HttpConfiguration cfg = new HttpConfiguration() HttpConfiguration cfg = new HttpConfiguration()

View File

@@ -0,0 +1,105 @@
/*
* 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.artifacts.Configuration
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Input
import org.gradle.api.Project
class ScmServerExtension implements Serializable {
private Project project
private Configuration configuration
private boolean openBrowser = true
private boolean liveReload = true
private File warFile
ScmServerExtension(Project project) {
this.project = project
}
@Input
public boolean isOpenBrowser() {
return openBrowser
}
public void setOpenBrowser(boolean openBrowser) {
this.openBrowser = openBrowser
}
@Input
public boolean isLiveReload() {
return liveReload
}
public void setLiveReload(boolean liveReload) {
this.liveReload = liveReload
}
@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
}
@Optional
@InputFile
public File getWarFile() {
return warFile
}
public void setWarFile(File warFile) {
this.warFile = warFile
}
@Optional
@Classpath
Configuration getConfiguration() {
return configuration
}
void setConfiguration(Configuration configuration) {
this.configuration = configuration
}
void configuration(String configuration) {
setConfiguration(project.configurations.getByName(configuration))
}
}

View File

@@ -33,6 +33,8 @@ import com.moowork.gradle.node.NodeExtension
class ServePlugin implements Plugin<Project> { class ServePlugin implements Plugin<Project> {
void apply(Project project) { void apply(Project project) {
def extension = project.extensions.create("scmServer", ScmServerExtension, project)
project.plugins.apply("com.github.node-gradle.node") project.plugins.apply("com.github.node-gradle.node")
def nodeExt = NodeExtension.get(project) def nodeExt = NodeExtension.get(project)
nodeExt.setDownload(true) nodeExt.setDownload(true)
@@ -40,8 +42,11 @@ class ServePlugin implements Plugin<Project> {
nodeExt.setYarnVersion('1.22.5') nodeExt.setYarnVersion('1.22.5')
nodeExt.setNodeModulesDir( project.rootProject.projectDir ) nodeExt.setNodeModulesDir( project.rootProject.projectDir )
project.tasks.register('write-server-config', WriteServerConfigTask) project.tasks.register('write-server-config', WriteServerConfigTask) {
it.extension = extension
}
project.tasks.register("serve", ServeTask) { project.tasks.register("serve", ServeTask) {
it.extension = extension
dependsOn 'write-server-config', 'yarnSetup' dependsOn 'write-server-config', 'yarnSetup'
} }
} }

View File

@@ -29,18 +29,72 @@ import com.moowork.gradle.node.yarn.YarnTask
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.Nested import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.api.GradleException
class ServeTask extends DefaultTask { class ServeTask extends DefaultTask {
private boolean frontend = true
private boolean waitForCompletion = true
private ScmServerExtension extension
@Nested
ScmServerExtension getExtension() {
return extension
}
void setExtension(ScmServerExtension extension) {
this.extension = extension
}
@Input
boolean isFrontend() {
return frontend
}
void setFrontend(boolean frontend) {
this.frontend = frontend
}
@Input
boolean isWaitForCompletion() {
return waitForCompletion
}
void setWaitForCompletion(boolean waitForCompletion) {
this.waitForCompletion = waitForCompletion
}
@TaskAction @TaskAction
void exec() { void exec() {
List<Closure<Void>> actions = new ArrayList<>(); List<Closure<Void>> actions = new ArrayList<>();
actions.add(createBackend()) actions.add(createBackend())
if (frontend) {
actions.add(createFrontend()) actions.add(createFrontend())
}
def threads = start(actions) def threads = start(actions)
if (waitForCompletion) {
wait(threads) wait(threads)
} else {
waitForPortToBeOpen()
}
}
private void waitForPortToBeOpen() {
int retries = 180
for (int i=0; i<retries; i++) {
try {
URL urlConnect = new URL("http://localhost:${extension.port}/scm/api/v2");
URLConnection conn = (HttpURLConnection) urlConnect.openConnection();
if (conn.getResponseCode() == 200) {
return
}
} catch (IOException ex) {
Thread.sleep(500)
}
}
throw new GradleException("scm-server not reachable")
} }
private static void wait(List<Thread> threads) { private static void wait(List<Thread> threads) {

View File

@@ -0,0 +1,58 @@
/*
* 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.tasks.Nested
import org.gradle.api.tasks.TaskAction
class StopScmServer extends DefaultTask {
private ScmServerExtension extension
@Nested
ScmServerExtension getExtension() {
return extension
}
void setExtension(ScmServerExtension extension) {
this.extension = extension
}
@TaskAction
void exec() {
URL url = new URL("http://localhost:${extension.port}/shutdown?token=_shutdown_")
try {
HttpURLConnection connection = (HttpURLConnection )url.openConnection()
connection.setRequestMethod("POST")
// ???
connection.getResponseCode()
} catch (IOException ex) {
// already closed ?
}
}
}

View File

@@ -33,8 +33,9 @@ import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Internal
import org.gradle.api.GradleException
import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
@@ -48,25 +49,15 @@ import groovy.json.JsonOutput
class WriteServerConfigTask extends DefaultTask { class WriteServerConfigTask extends DefaultTask {
@Input private ScmServerExtension extension
public String getHome() {
if (project.hasProperty('home')) { @Nested
return project.getProperty('home') ScmServerExtension getExtension() {
} return extension
return new File(project.buildDir, 'scm-home').toString()
} }
@Input void setExtension(ScmServerExtension extension) {
public int getPort() { this.extension = extension
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 @OutputFile
@@ -76,17 +67,37 @@ class WriteServerConfigTask extends DefaultTask {
@TaskAction @TaskAction
void execute() { void execute() {
File warFile = extension.getWarFile()
if (warFile == null) {
Configuration configuration = extension.getConfiguration()
if (configuration == null) {
throw new GradleException("warFile or configuration must be used")
}
def artificat = configuration.resolvedConfiguration
.resolvedArtifacts
.find {
it.extension == 'war'
}
if (artificat == null) {
throw new GradleException("could not find war file in configuration")
}
warFile = artificat.getFile()
}
File serverConfig = getServerConfig() File serverConfig = getServerConfig()
serverConfig.getParentFile().mkdirs() serverConfig.getParentFile().mkdirs()
serverConfig.text = JsonOutput.toJson([ serverConfig.text = JsonOutput.toJson([
home: getHome(), home: extension.getHome(),
port: getPort(), port: extension.getPort(),
contextPath: '/scm', contextPath: '/scm',
stage: 'DEVELOPMENT', stage: 'DEVELOPMENT',
headerSize: 16384, headerSize: 16384,
openBrowser: true, openBrowser: extension.openBrowser,
warFile: getWarFile().toString(), warFile: warFile.toString(),
livereloadUrl: 'http://localhost:3000' livereloadUrl: extension.liveReload ? 'http://localhost:3000' : null
]) ])
} }

View File

@@ -22,4 +22,4 @@
# SOFTWARE. # SOFTWARE.
# #
version=2.3.0-SNAPSHOT version=2.13.0-SNAPSHOT

74
scm-it/build.gradle Normal file
View File

@@ -0,0 +1,74 @@
/*
* 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.
*/
plugins {
id 'java-library'
id 'org.scm-manager.integration-tests'
}
configurations {
itWebApp
}
dependencies {
testImplementation platform(project(':'))
testImplementation project(':scm-core')
testImplementation project(':scm-test')
// TODO add tests
testImplementation project(':scm-plugins:scm-git-plugin')
testImplementation project(path: ':scm-plugins:scm-git-plugin', configuration: 'tests')
testImplementation project(':scm-plugins:scm-hg-plugin')
testImplementation project(path: ':scm-plugins:scm-hg-plugin', configuration: 'tests')
testImplementation project(':scm-plugins:scm-svn-plugin')
testImplementation project(path: ':scm-plugins:scm-svn-plugin', configuration: 'tests')
testImplementation 'io.rest-assured:rest-assured:4.3.0'
testImplementation 'org.glassfish:javax.json:1.1.4'
itWebApp project(path: ':scm-webapp', configuration: 'webapp')
}
scmServer {
configuration 'itWebApp'
openBrowser = false
liveReload = false
}
test {
include '**/*Test.class'
exclude '**/*ITCase.class'
}
task integrationTest(type: Test) {
include '**/*ITCase.class'
exclude '**/*Test.class'
dependsOn 'test'
doFirst {
tasks.getByName('startScmServer').exec()
}
finalizedBy 'stopScmServer'
}

View File

@@ -28,7 +28,8 @@ plugins {
} }
dependencies { dependencies {
implementation 'sonia.jgit:org.eclipse.jgit:5.6.1.202002131546-r-scm1' // required by scm-it
api 'sonia.jgit:org.eclipse.jgit:5.6.1.202002131546-r-scm1'
implementation 'sonia.jgit:org.eclipse.jgit.http.server:5.6.1.202002131546-r-scm1' implementation 'sonia.jgit:org.eclipse.jgit.http.server:5.6.1.202002131546-r-scm1'
implementation 'sonia.jgit:org.eclipse.jgit.lfs.server:5.6.1.202002131546-r-scm1' implementation 'sonia.jgit:org.eclipse.jgit.lfs.server:5.6.1.202002131546-r-scm1'
@@ -51,3 +52,19 @@ scmPlugin {
} }
} }
task testJar(type: Jar) {
classifier = 'tests'
from sourceSets.test.output
}
configurations {
tests {
canBeConsumed = true
canBeResolved = false
}
}
artifacts {
tests(testJar)
}

View File

@@ -52,3 +52,19 @@ scmPlugin {
} }
} }
task testJar(type: Jar) {
classifier = 'tests'
from sourceSets.test.output
}
configurations {
tests {
canBeConsumed = true
canBeResolved = false
}
}
artifacts {
tests(testJar)
}

View File

@@ -52,6 +52,22 @@ scmPlugin {
} }
task testJar(type: Jar) {
classifier = 'tests'
from sourceSets.test.output
}
configurations {
tests {
canBeConsumed = true
canBeResolved = false
}
}
artifacts {
tests(testJar)
}
/* /*
<!-- <!--
SCMSvnDiffGenerator is a copy of an internal SVNKit class, with small changes for SCM-Manger. SCMSvnDiffGenerator is a copy of an internal SVNKit class, with small changes for SCM-Manger.

View File

@@ -161,6 +161,12 @@ task 'dev-war' (type: War) {
dependsOn 'copy-core-plugins' dependsOn 'copy-core-plugins'
} }
scmServer {
liveReload = true
openBrowser = true
warFile = file('build/libs/scm-webapp-dev.war')
}
serve { serve {
dependsOn 'dev-war' dependsOn 'dev-war'
} }

View File

@@ -44,5 +44,6 @@ include 'scm-packaging:deb'
include 'scm-packaging:rpm' include 'scm-packaging:rpm'
include 'scm-packaging:docker' include 'scm-packaging:docker'
include 'scm-packaging:helm' include 'scm-packaging:helm'
include 'scm-it'
includeBuild '../gradle-smp-plugin' includeBuild '../gradle-smp-plugin'