diff --git a/doc-gitlab-runner.md b/doc-gitlab-runner.md
new file mode 100644
index 0000000..14353c5
--- /dev/null
+++ b/doc-gitlab-runner.md
@@ -0,0 +1,10 @@
+# gitlab runner
+
+command used to register new runner
+
+```shell script
+$ docker run -d --name gitlab-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest
+
+$ gitlab-runner register -non-interactive --description "manualy registered gitlab runner" --url "http://172.17.0.1
+:8080/" --registration-token "registration_token" --tag-list "docker,manual"
+```
diff --git a/pom.xml b/pom.xml
index 6ae4dc3..efdbc33 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,10 @@
org.springframework.boot
spring-boot-starter-undertow
-->
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
diff --git a/src/main/java/tk/antoine_roux/wiki/Constant.java b/src/main/java/tk/antoine_roux/wiki/Constant.java
new file mode 100644
index 0000000..815dcb8
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/Constant.java
@@ -0,0 +1,11 @@
+package tk.antoine_roux.wiki;
+
+/**
+ * Application level constant
+ */
+public final class Constant {
+ public static final String API_PREFIX = "/api";
+ public static final String API_NAME = "gitlab-runner-gateway";
+ public static final String API_VERSION = "4";
+ public static final String VERSION_PREFIX = "v";
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/ControllerHandlers.java b/src/main/java/tk/antoine_roux/wiki/ControllerHandlers.java
new file mode 100644
index 0000000..21f774d
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/ControllerHandlers.java
@@ -0,0 +1,58 @@
+package tk.antoine_roux.wiki;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import tk.antoine_roux.wiki.annotation.ApiPrefix;
+import tk.antoine_roux.wiki.annotation.ApiVersion;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import static tk.antoine_roux.wiki.Constant.*;
+
+@RestController
+@ApiPrefix(API_PREFIX)
+public class ControllerHandlers {
+
+ private RunnerRegistrar runnerRegistrar;
+
+ @Autowired
+ public ControllerHandlers(RunnerRegistrar runnerRegistrar) {
+ this.runnerRegistrar = runnerRegistrar;
+ }
+
+ /**
+ * add register new runners
+ *
+ * @param body
+ * @return
+ */
+ @ResponseBody
+ @ApiVersion({API_VERSION})
+ @PostMapping(value = "/runners", produces = APPLICATION_JSON_VALUE)
+ public static ResponseEntity addRunner(@RequestBody String body) {
+ System.out.println(body);
+ return ResponseEntity.ok(body);
+ }
+
+ /**
+ * hello test endpoint
+ *
+ * @return
+ */
+ @ResponseBody
+ @GetMapping("/info")
+ public static ResponseEntity> info() {
+ return ResponseEntity.ok(
+ // sort attribute by key name
+ new TreeMap<>(
+ Map.of(
+ "api-version", VERSION_PREFIX + API_VERSION,
+ "api-name", API_NAME
+ )
+ )
+ );
+ }
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/MainLauncher.java b/src/main/java/tk/antoine_roux/wiki/MainLauncher.java
index 31c634d..3a6f6cc 100644
--- a/src/main/java/tk/antoine_roux/wiki/MainLauncher.java
+++ b/src/main/java/tk/antoine_roux/wiki/MainLauncher.java
@@ -1,9 +1,7 @@
package tk.antoine_roux.wiki;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
@@ -15,9 +13,6 @@ import org.springframework.web.servlet.function.ServerResponse;
@SpringBootApplication(proxyBeanMethods = false)
public class MainLauncher {
- @Value("${wikiproject.basePath}")
- private String basePath;
-
/**
* Entrypoint for application
*/
@@ -28,11 +23,11 @@ public class MainLauncher {
/**
* Routing declaration
*/
- @Bean
+ // @Bean
public RouterFunction routes() {
return RouterFunctions.route()
- .GET(this.basePath + "/hello", serverRequest ->
- ServerResponse.ok().body("Hello world !")
- ).build();
+ // .POST("/runners", accept(APPLICATION_FORM_URLENCODED), ControllerHandlers::addRunner)
+ // .GET("/hello", ControllerHandlers::hello)
+ .build();
}
}
diff --git a/src/main/java/tk/antoine_roux/wiki/RunnerRegistrar.java b/src/main/java/tk/antoine_roux/wiki/RunnerRegistrar.java
new file mode 100644
index 0000000..cb66987
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/RunnerRegistrar.java
@@ -0,0 +1,41 @@
+package tk.antoine_roux.wiki;
+
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class use to perist registered gitlab runner
+ */
+@Service
+public class RunnerRegistrar {
+ private final List runners = new ArrayList<>();
+
+ public List getRunners() {
+ return this.runners;
+ }
+
+ public void addRunner(Runner r) {
+ this.runners.add(r);
+ }
+
+ /**
+ * in memory representation of gitlab runner
+ */
+ public static class Runner {
+ private static final String TAG_SEPARATOR = ",";
+
+ public String id;
+ public String description;
+ public String[] tags;
+ public String registrationToken;
+
+ public Runner(String id, String description, String tags, String registrationToken) {
+ this.id = id;
+ this.description = description;
+ this.tags = tags.split(TAG_SEPARATOR);
+ this.registrationToken = registrationToken;
+ }
+ }
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/annotation/ApiPrefix.java b/src/main/java/tk/antoine_roux/wiki/annotation/ApiPrefix.java
new file mode 100644
index 0000000..2d2b922
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/annotation/ApiPrefix.java
@@ -0,0 +1,12 @@
+package tk.antoine_roux.wiki.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ApiPrefix {
+ String value() default "";
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/annotation/ApiVersion.java b/src/main/java/tk/antoine_roux/wiki/annotation/ApiVersion.java
new file mode 100644
index 0000000..11d6c93
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/annotation/ApiVersion.java
@@ -0,0 +1,12 @@
+package tk.antoine_roux.wiki.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ApiVersion {
+ String[] value() default {""};
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/configuration/ApiVersionRequestMappingHandlerMapping.java b/src/main/java/tk/antoine_roux/wiki/configuration/ApiVersionRequestMappingHandlerMapping.java
new file mode 100644
index 0000000..6955534
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/configuration/ApiVersionRequestMappingHandlerMapping.java
@@ -0,0 +1,91 @@
+package tk.antoine_roux.wiki.configuration;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.web.servlet.mvc.condition.*;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import tk.antoine_roux.wiki.annotation.ApiPrefix;
+import tk.antoine_roux.wiki.annotation.ApiVersion;
+
+import java.lang.reflect.Method;
+
+/**
+ * create custom {@link org.springframework.web.bind.annotation.RequestMapping} Handler to add versioning into uri
+ */
+public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
+
+ private final String versionPrefix;
+
+ /**
+ * create @{@link org.springframework.web.bind.annotation.RequestMapping} handler classe
+ * this class add some prefix to uri
+ *
+ * @param versionPrefix
+ */
+ public ApiVersionRequestMappingHandlerMapping(String versionPrefix) {
+ this.versionPrefix = versionPrefix;
+ }
+
+ @Override
+ protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
+ RequestMappingInfo info = super.getMappingForMethod(method, handlerType);
+ if (info == null) {
+ return null;
+ }
+
+ ApiVersion methodAnnotation = AnnotationUtils.findAnnotation(method, ApiVersion.class);
+ if (methodAnnotation != null) {
+ RequestCondition> methodCondition = this.getCustomMethodCondition(method);
+ // Concatenate our ApiVersion with the usual request mapping
+ info = this.createApiVersionInfo(methodAnnotation, methodCondition).combine(info);
+ } else {
+ ApiVersion typeAnnotation = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
+ if (typeAnnotation != null) {
+ RequestCondition> typeCondition = this.getCustomTypeCondition(handlerType);
+ // Concatenate our ApiVersion with the usual request mapping
+ info = this.createApiVersionInfo(typeAnnotation, typeCondition).combine(info);
+ }
+ }
+
+ ApiPrefix annotationApiPrefix = AnnotationUtils.findAnnotation(handlerType, ApiPrefix.class);
+ if (annotationApiPrefix != null) {
+ RequestMappingInfo requestMappingInfo = new RequestMappingInfo(
+ new PatternsRequestCondition(
+ new String[]{annotationApiPrefix.value()},
+ this.getUrlPathHelper(), this.getPathMatcher(),
+ false
+ ),
+ new RequestMethodsRequestCondition(),
+ new ParamsRequestCondition(),
+ new HeadersRequestCondition(),
+ new ConsumesRequestCondition(),
+ new ProducesRequestCondition(),
+ null);
+ info = requestMappingInfo.combine(info);
+ }
+
+ return info;
+ }
+
+ private RequestMappingInfo createApiVersionInfo(ApiVersion annotation, RequestCondition> customCondition) {
+ String[] values = annotation.value();
+ String[] patterns = new String[values.length];
+ for (int i = 0; i < values.length; i++) {
+ // Build the URL prefix
+ patterns[i] = this.versionPrefix + values[i];
+ }
+
+ return new RequestMappingInfo(
+ new PatternsRequestCondition(
+ patterns, this.getUrlPathHelper(), this.getPathMatcher(),
+ false
+ // , this.useTrailingSlashMatch(), this.getFileExtensions()
+ ),
+ new RequestMethodsRequestCondition(),
+ new ParamsRequestCondition(),
+ new HeadersRequestCondition(),
+ new ConsumesRequestCondition(),
+ new ProducesRequestCondition(),
+ customCondition);
+ }
+}
diff --git a/src/main/java/tk/antoine_roux/wiki/configuration/WebConfiguration.java b/src/main/java/tk/antoine_roux/wiki/configuration/WebConfiguration.java
new file mode 100644
index 0000000..b7907dd
--- /dev/null
+++ b/src/main/java/tk/antoine_roux/wiki/configuration/WebConfiguration.java
@@ -0,0 +1,25 @@
+package tk.antoine_roux.wiki.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.support.FormattingConversionService;
+import org.springframework.web.accept.ContentNegotiationManager;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import org.springframework.web.servlet.resource.ResourceUrlProvider;
+import tk.antoine_roux.wiki.Constant;
+
+/**
+ * spring web configuration
+ */
+@Configuration
+public class WebConfiguration extends WebMvcConfigurationSupport {
+
+ @Bean
+ @Override
+ public RequestMappingHandlerMapping requestMappingHandlerMapping(ContentNegotiationManager contentNegotiationManager,
+ FormattingConversionService conversionService,
+ ResourceUrlProvider resourceUrlProvider) {
+ return new ApiVersionRequestMappingHandlerMapping(Constant.VERSION_PREFIX);
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index c177a09..822417f 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,7 +1,15 @@
spring.main.banner-mode=off
-spring.main.lazy-initialization=true
+spring.main.lazy-initialization=false
spring.output.ansi.enabled=ALWAYS
server.port=^application.port^
-wikiproject.basePath=/wikiproject
+# wikiproject.basePath=/api
+
+logging.level.root=INFO
+
+# spring boot actuator
+management.server.port=8080
+info.name=gitlab-runner-gateway
+info.more.detail=This is a REST API use to gateway gitlab runner call to gitlab instance
+management.endpoints.web.exposure.include=mappings