Browse Source

start .gitlab-ci.yml parsing

master
Antoine 6 months ago
parent
commit
8283da89b2
Signed by: antoine <antoinroux@hotmail.fr> GPG Key ID: 098FB66FC0475E70
36 changed files with 514 additions and 184 deletions
  1. +1
    -0
      .gitignore
  2. +10
    -0
      pom.xml
  3. +16
    -9
      src/main/java/tk/antoine_roux/wiki/ControllerHandlers.java
  4. +3
    -0
      src/main/java/tk/antoine_roux/wiki/MainLauncher.java
  5. +50
    -0
      src/main/java/tk/antoine_roux/wiki/configuration/GitConfiguration.java
  6. +20
    -0
      src/main/java/tk/antoine_roux/wiki/configuration/WebConfiguration.java
  7. +46
    -0
      src/main/java/tk/antoine_roux/wiki/model/internal/GitlabCI.java
  8. +0
    -56
      src/main/java/tk/antoine_roux/wiki/model/internal/HookEvent.java
  9. +0
    -93
      src/main/java/tk/antoine_roux/wiki/model/internal/Job.java
  10. +0
    -12
      src/main/java/tk/antoine_roux/wiki/model/internal/JobStatus.java
  11. +1
    -0
      src/main/java/tk/antoine_roux/wiki/model/request/AddRunner.java
  12. +55
    -0
      src/main/java/tk/antoine_roux/wiki/model/request/HookEvent.java
  13. +2
    -0
      src/main/java/tk/antoine_roux/wiki/model/request/JobRequest.java
  14. +2
    -2
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/Commit.java
  15. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/InternalTracker.java
  16. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/Permission.java
  17. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/Repository.java
  18. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/RunnerInfo.java
  19. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/User.java
  20. +1
    -1
      src/main/java/tk/antoine_roux/wiki/model/request/secondary/UserReduced.java
  21. +33
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/JobResponse.java
  22. +19
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Artifact.java
  23. +10
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Cache.java
  24. +8
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Credential.java
  25. +16
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Dependency.java
  26. +16
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/GitInfo.java
  27. +8
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/GitLabFeatures.java
  28. +26
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Image.java
  29. +14
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/JobInfo.java
  30. +15
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/JobVariable.java
  31. +5
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/RunnerInfo.java
  32. +33
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Secret.java
  33. +14
    -0
      src/main/java/tk/antoine_roux/wiki/model/response/secondary/Step.java
  34. +75
    -0
      src/main/java/tk/antoine_roux/wiki/service/GitService.java
  35. +6
    -6
      src/main/java/tk/antoine_roux/wiki/service/JobManager.java
  36. +4
    -0
      src/main/resources/application.properties

+ 1
- 0
.gitignore View File

@@ -3,3 +3,4 @@
target/

testGit/
application-local.properties

+ 10
- 0
pom.xml View File

@@ -34,6 +34,7 @@
<spring-graalvm-native.version>0.8.0</spring-graalvm-native.version>
<native-image-maven-plugin.version>20.2.0</native-image-maven-plugin.version>
<jackson-datatype.version>2.11.2</jackson-datatype.version>
<org.eclipse.jgit.version>5.9.0.202009080501-r</org.eclipse.jgit.version>
</properties>

<dependencies>
@@ -60,10 +61,19 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>${org.eclipse.jgit.version}</version>
</dependency>
</dependencies>

<build>


+ 16
- 9
src/main/java/tk/antoine_roux/wiki/ControllerHandlers.java View File

@@ -1,5 +1,6 @@
package tk.antoine_roux.wiki;

import org.eclipse.jgit.api.errors.GitAPIException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -9,17 +10,20 @@ import org.springframework.web.bind.annotation.*;
import tk.antoine_roux.wiki.annotation.ApiPrefix;
import tk.antoine_roux.wiki.annotation.ApiVersion;
import tk.antoine_roux.wiki.configuration.Exception.DeleteRunnerException;
import tk.antoine_roux.wiki.model.internal.HookEvent;
import tk.antoine_roux.wiki.model.internal.Job;
import tk.antoine_roux.wiki.model.internal.GitlabCI;
import tk.antoine_roux.wiki.model.internal.Runner;
import tk.antoine_roux.wiki.model.request.AddRunner;
import tk.antoine_roux.wiki.model.request.HookEvent;
import tk.antoine_roux.wiki.model.request.JobRequest;
import tk.antoine_roux.wiki.model.request.TokenRunner;
import tk.antoine_roux.wiki.model.response.JobResponse;
import tk.antoine_roux.wiki.model.response.RegisterRunnerResponse;
import tk.antoine_roux.wiki.service.GitService;
import tk.antoine_roux.wiki.service.JobManager;
import tk.antoine_roux.wiki.service.RunnerRegistrar;
import tk.antoine_roux.wiki.utilitary.Boolean;

import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Map;
import java.util.Optional;
@@ -35,11 +39,13 @@ public class ControllerHandlers {

private final RunnerRegistrar runnerRegistrar;
private final JobManager jobManager;
private final GitService gitService;

@Autowired
public ControllerHandlers(RunnerRegistrar runnerRegistrar, JobManager jobManager) {
public ControllerHandlers(RunnerRegistrar runnerRegistrar, JobManager jobManager, GitService gitService) {
this.runnerRegistrar = runnerRegistrar;
this.jobManager = jobManager;
this.gitService = gitService;
}

/**
@@ -102,8 +108,8 @@ public class ControllerHandlers {

@ApiVersion(API_VERSION)
@PostMapping("/jobs/request")
public ResponseEntity<Job> jobRequest(@RequestBody JobRequest jobRequest) {
Optional<Job> currentJob = this.jobManager.popJob(jobRequest);
public ResponseEntity<JobResponse> jobRequest(@RequestBody JobRequest jobRequest) {
Optional<JobResponse> currentJob = this.jobManager.popJob(jobRequest);
return currentJob
.map(job -> ResponseEntity.status(HttpStatus.CREATED).body(job))
.orElseGet(() -> ResponseEntity.noContent().build());
@@ -118,12 +124,13 @@ public class ControllerHandlers {

@ApiVersion(API_VERSION)
@PostMapping("/webhook")
public ResponseEntity<Void> webhook(@RequestBody HookEvent webHookData) {
public ResponseEntity<Void> webhook(@RequestBody HookEvent webHookData) throws IOException, GitAPIException {
ResponseEntity.BodyBuilder responseEntity;
Optional<Job> job = webHookData.toJob();
Optional<GitlabCI> gitlabCI = this.gitService.getYMLGitlabCI(webHookData);

if (job.isPresent()) {
this.jobManager.stackJob(job.get());
if (gitlabCI.isPresent()) {
JobResponse job = gitlabCI.get().buildJobResponse();
this.jobManager.stackJob(job);
responseEntity = ResponseEntity.ok();
} else {
responseEntity = ResponseEntity.unprocessableEntity();


+ 3
- 0
src/main/java/tk/antoine_roux/wiki/MainLauncher.java View File

@@ -2,15 +2,18 @@ package tk.antoine_roux.wiki;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
import tk.antoine_roux.wiki.configuration.GitConfiguration;

/**
* Main class
*/
// force spring application to not use glibc or any non jdk code which is bad for graalvm
@SpringBootApplication(proxyBeanMethods = false)
@EnableConfigurationProperties(GitConfiguration.GitlabCIContextProperties.class)
public class MainLauncher {

/**


+ 50
- 0
src/main/java/tk/antoine_roux/wiki/configuration/GitConfiguration.java View File

@@ -0,0 +1,50 @@
package tk.antoine_roux.wiki.configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration(proxyBeanMethods = false)
public class GitConfiguration {

@Bean
public YAMLFactory yamlFactory() {
return YAMLFactory.builder().build();
}

@Bean(name = "YAMLObjectMapper")
public ObjectMapper ObjectMapper(YAMLFactory yamlFactory) {
return new ObjectMapper(yamlFactory);
}

@Bean
public UsernamePasswordCredentialsProvider credentialsProvider(GitlabCIContextProperties gitlabCIContextProperties, Environment environment) {
return new UsernamePasswordCredentialsProvider(gitlabCIContextProperties.getUsername(), gitlabCIContextProperties.getPassword());
}

@ConfigurationProperties("gitlab-ci")
public static class GitlabCIContextProperties {
private String username;
private String password;

public String getUsername() {
return this.username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return this.password;
}

public void setPassword(String password) {
this.password = password;
}
}
}

+ 20
- 0
src/main/java/tk/antoine_roux/wiki/configuration/WebConfiguration.java View File

@@ -1,7 +1,13 @@
package tk.antoine_roux.wiki.configuration;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import tk.antoine_roux.wiki.utilitary.Constant;

@@ -17,4 +23,18 @@ public class WebConfiguration implements WebMvcRegistrations {
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiVersionRequestMappingHandlerMapping(Constant.VERSION_PREFIX);
}

/**
* build default Spring boot {@link ObjectMapper}
* this bean avoid spring boot to auto detect {@link GitConfiguration#ObjectMapper(YAMLFactory)}
* as default {@link ObjectMapper}
*
* @param jackson2ObjectMapperBuilder
* @return
*/
@Bean
@Primary
public ObjectMapper jackson2ObjectMapperBuilder(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
return jackson2ObjectMapperBuilder.build();
}
}

+ 46
- 0
src/main/java/tk/antoine_roux/wiki/model/internal/GitlabCI.java View File

@@ -0,0 +1,46 @@
package tk.antoine_roux.wiki.model.internal;

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import tk.antoine_roux.wiki.model.response.JobResponse;

import java.util.Collections;
import java.util.List;
import java.util.Map;

public class GitlabCI {
public String image;
@JsonProperty("before_script")
public List<String> beforeScript = Collections.emptyList();
@JsonProperty("after_script")
public List<String> afterScript = Collections.emptyList();
public Map<String, Job> jobs = Collections.emptyMap();

@JsonAnySetter
public void setJobs(String key, Job value) {
this.jobs.put(key, value);
}

public JobResponse buildJobResponse() {
return null;
}

public enum RuleEnum {
IF("if");

String content;

RuleEnum(String s) {
this.content = s;
}
}

private static class Job {
public String stage;
public String image;
public Map<String, String> variables = Collections.emptyMap();
public List<String> services = Collections.emptyList();
public Map<RuleEnum, String> rules = Collections.emptyMap();
public List<String> script = Collections.emptyList();
}
}

+ 0
- 56
src/main/java/tk/antoine_roux/wiki/model/internal/HookEvent.java View File

@@ -1,56 +0,0 @@
package tk.antoine_roux.wiki.model.internal;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

public class HookEvent {
public String secret;
public String ref;
public String before;
public String after;
@JsonProperty("compare_url")
public String compareUrl;
public List<Commit> commits;
@JsonProperty("head_commit")
public String headCommit;
public Repository repository;
public User pusher;
public User sender;

AtomicInteger idIncrementer = new AtomicInteger();

/**
* convert {@link HookEvent} to {@link Job} if possible
* else return and {@link Optional#empty()}
*/
public Optional<Job> toJob() {
Optional<Job> optJob;

if (this.commits.isEmpty()) {
optJob = Optional.empty();
} else {
// search for head commit or take first in event's list of commit
Commit commit = this.commits.stream().filter(co -> co.id.equals(this.headCommit))
.findFirst().orElse(this.commits.get(0));

Job.Commit co = new Job.Commit(
commit.author.email, commit.author.name, commit.timestamp,
commit.id, commit.message, commit.id.substring(0, 8), commit.message
);

Job job = new Job(
null, co, null, ZonedDateTime.now(), null,
this.idIncrementer.getAndIncrement(), UUID.randomUUID().toString(), this.ref,
null, "root", null, JobStatus.CREATED, false, this.pusher.toReducedUser()
);
optJob = Optional.of(job);
}

return optJob;
}
}

+ 0
- 93
src/main/java/tk/antoine_roux/wiki/model/internal/Job.java View File

@@ -1,93 +0,0 @@
package tk.antoine_roux.wiki.model.internal;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.time.ZonedDateTime;

// ID int `json:"id"`
// Token string `json:"token"`
// AllowGitFetch bool `json:"allow_git_fetch"`
// JobInfo JobInfo `json:"job_info"`
// GitInfo GitInfo `json:"git_info"`
// RunnerInfo RunnerInfo `json:"runner_info"`
// Variables JobVariables `json:"variables"`
// Steps Steps `json:"steps"`
// Image Image `json:"image"`
// Services Services `json:"services"`
// Artifacts Artifacts `json:"artifacts"`
// Cache Caches `json:"cache"`
// Credentials []Credentials `json:"credentials"`
// Dependencies Dependencies `json:"dependencies"`
// Features GitlabFeatures `json:"features"`
// Secrets Secrets `json:"secrets,omitempty"`

public class Job {
@JsonProperty("artifacts_file")
public String artifactsFile;
public Commit commit;
public String coverage;
@JsonProperty("created_at")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssSSSXXX")
public ZonedDateTime createdAt;
@JsonProperty("finished_at")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssSSSXXX")
public ZonedDateTime finishedAt;
public Integer id;
public String name;
public String ref;
public Runner runner;
public String stage;
@JsonProperty("started_at")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssSSSXXX")
public ZonedDateTime startedAt;
public JobStatus status;
public boolean tag;
public UserReduced user;

public Job(
String artifactsFile, Commit commit, String coverage, ZonedDateTime createdAt, ZonedDateTime finishedAt,
Integer id, String name, String ref, Runner runner, String stage, ZonedDateTime startedAt, JobStatus status,
boolean tag, UserReduced user
) {
this.artifactsFile = artifactsFile;
this.commit = commit;
this.coverage = coverage;
this.createdAt = createdAt;
this.finishedAt = finishedAt;
this.id = id;
this.name = name;
this.ref = ref;
this.runner = runner;
this.stage = stage;
this.startedAt = startedAt;
this.status = status;
this.tag = tag;
this.user = user;
}

public static class Commit {
@JsonProperty("author_email")
public String authorEmail;
@JsonProperty("author_name")
public String authorName;
@JsonProperty("created_at")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssSSSXXX")
public ZonedDateTime createdAt;
public String id;
public String message;
@JsonProperty("short_id")
public String shortId;
public String title;

public Commit(String authorEmail, String authorName, ZonedDateTime createdAt, String id, String message, String shortId, String title) {
this.authorEmail = authorEmail;
this.authorName = authorName;
this.createdAt = createdAt;
this.id = id;
this.message = message;
this.shortId = shortId;
this.title = title;
}
}
}

+ 0
- 12
src/main/java/tk/antoine_roux/wiki/model/internal/JobStatus.java View File

@@ -1,12 +0,0 @@
package tk.antoine_roux.wiki.model.internal;

/**
* This enum represent all state a job could take during
* his lifecycle
*/
public enum JobStatus {
CREATED,
STARTED,
STOPPED,
FINISHED
}

+ 1
- 0
src/main/java/tk/antoine_roux/wiki/model/request/AddRunner.java View File

@@ -1,6 +1,7 @@
package tk.antoine_roux.wiki.model.request;

import com.fasterxml.jackson.annotation.JsonProperty;
import tk.antoine_roux.wiki.model.request.secondary.RunnerInfo;

import java.util.Arrays;
import java.util.List;


+ 55
- 0
src/main/java/tk/antoine_roux/wiki/model/request/HookEvent.java View File

@@ -0,0 +1,55 @@
package tk.antoine_roux.wiki.model.request;

import com.fasterxml.jackson.annotation.JsonProperty;
import tk.antoine_roux.wiki.model.request.secondary.Commit;
import tk.antoine_roux.wiki.model.request.secondary.Repository;
import tk.antoine_roux.wiki.model.request.secondary.User;

import java.util.List;

public class HookEvent {
public String secret;
public String ref;
public String before;
public String after;
@JsonProperty("compare_url")
public String compareUrl;
public List<Commit> commits;
@JsonProperty("head_commit")
public String headCommit;
public Repository repository;
public User pusher;
public User sender;

// AtomicInteger idIncrementer = new AtomicInteger();
//
// /**
// * convert {@link HookEvent} to {@link Job} if possible
// * else return and {@link Optional#empty()}
// */
// public Optional<Job> toJob() {
// Optional<Job> optJob;
//
// if (this.commits.isEmpty()) {
// optJob = Optional.empty();
// } else {
// // search for head commit or take first in event's list of commit
// Commit commit = this.commits.stream().filter(co -> co.id.equals(this.headCommit))
// .findFirst().orElse(this.commits.get(0));
//
// Job.Commit co = new Job.Commit(
// commit.author.email, commit.author.name, commit.timestamp,
// commit.id, commit.message, commit.id.substring(0, 8), commit.message
// );
//
// Job job = new Job(
// null, co, null, ZonedDateTime.now(), null,
// this.idIncrementer.getAndIncrement(), UUID.randomUUID().toString(), this.ref,
// null, "root", null, JobStatus.CREATED, false, this.pusher.toReducedUser()
// );
// optJob = Optional.of(job);
// }
//
// return optJob;
// }
}

+ 2
- 0
src/main/java/tk/antoine_roux/wiki/model/request/JobRequest.java View File

@@ -1,5 +1,7 @@
package tk.antoine_roux.wiki.model.request;

import tk.antoine_roux.wiki.model.request.secondary.RunnerInfo;

/**
* Job Request compose from {@link RunnerInfo} and token field
*/


src/main/java/tk/antoine_roux/wiki/model/internal/Commit.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/Commit.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

import com.fasterxml.jackson.annotation.JsonFormat;

@@ -13,7 +13,7 @@ public class Commit {
public UserReduced committer;
public String verification;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
public ZonedDateTime timestamp;

public List<String> added;

src/main/java/tk/antoine_roux/wiki/model/internal/InternalTracker.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/InternalTracker.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;


src/main/java/tk/antoine_roux/wiki/model/internal/Permission.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/Permission.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

/**
* model about repository permission

src/main/java/tk/antoine_roux/wiki/model/internal/Repository.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/Repository.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;


src/main/java/tk/antoine_roux/wiki/model/request/RunnerInfo.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/RunnerInfo.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.request;
package tk.antoine_roux.wiki.model.request.secondary;

import java.util.Map;


src/main/java/tk/antoine_roux/wiki/model/internal/User.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/User.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;


src/main/java/tk/antoine_roux/wiki/model/internal/UserReduced.java → src/main/java/tk/antoine_roux/wiki/model/request/secondary/UserReduced.java View File

@@ -1,4 +1,4 @@
package tk.antoine_roux.wiki.model.internal;
package tk.antoine_roux.wiki.model.request.secondary;

/**
* Reduced user information

+ 33
- 0
src/main/java/tk/antoine_roux/wiki/model/response/JobResponse.java View File

@@ -0,0 +1,33 @@
package tk.antoine_roux.wiki.model.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import tk.antoine_roux.wiki.model.response.secondary.*;

import java.util.List;
import java.util.Map;

/**
* job format use to submit
* information to gitlab-runner
*/
public class JobResponse {
public Integer id;
public String token;
@JsonProperty("allow_git_fetch")
public boolean allowGitFetch;
@JsonProperty("job_info")
public JobInfo jobInfo;
@JsonProperty("git_info")
public GitInfo gitInfo;
public RunnerInfo runnerInfo;
public List<JobVariable> variables;
public List<Step> steps;
public Image image;
public List<Image> services;
public List<Artifact> artifacts;
public List<Cache> cache;
public List<Credential> credentials;
public List<Dependency> dependencies;
public GitLabFeatures features;
public Map<String, Secret> secrets;
}

+ 19
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Artifact.java View File

@@ -0,0 +1,19 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class Artifact {
public String name;
public boolean untracked;
public List<String> paths;
public List<String> exclude;
public String when;
@JsonProperty("artifact_type")
public String artifactType;
@JsonProperty("artifact_format")
public String artifactFormat;
@JsonProperty("expire_in")
public String expireIn;
}

+ 10
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Cache.java View File

@@ -0,0 +1,10 @@
package tk.antoine_roux.wiki.model.response.secondary;

import java.util.List;

public class Cache {
public String key;
public boolean untracked;
public String policy;
public List<String> paths;
}

+ 8
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Credential.java View File

@@ -0,0 +1,8 @@
package tk.antoine_roux.wiki.model.response.secondary;

public class Credential {
public String type;
public String url;
public String username;
public String password;
}

+ 16
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Dependency.java View File

@@ -0,0 +1,16 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

public class Dependency {
public int id;
public String token;
public String name;
@JsonProperty("artifacts_file")
public DependencyArtifactsFile artifactsFile;

public static class DependencyArtifactsFile {
public String filename;
public int size;
}
}

+ 16
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/GitInfo.java View File

@@ -0,0 +1,16 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

public class GitInfo {
@JsonProperty("repo_url")
public String repoURL;
public String ref;
public String sha;
@JsonProperty("before_sha")
public String beforeSha;
@JsonProperty("ref_type")
public String refType;
public String[] refspecs;
public int depth;
}

+ 8
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/GitLabFeatures.java View File

@@ -0,0 +1,8 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

public class GitLabFeatures {
@JsonProperty("trace_sections")
public boolean traceSections;
}

+ 26
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Image.java View File

@@ -0,0 +1,26 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.List;

public class Image {
public String name;
@JsonInclude(JsonInclude.Include.NON_NULL)
public String alias;
@JsonInclude(JsonInclude.Include.NON_NULL)
public List<String> command;
@JsonInclude(JsonInclude.Include.NON_NULL)
public List<String> entrypoint;
@JsonInclude(JsonInclude.Include.NON_NULL)
public Port ports;

static class Port {
@JsonInclude(JsonInclude.Include.NON_NULL)
public String name;
@JsonInclude(JsonInclude.Include.NON_NULL)
public int number;
@JsonInclude(JsonInclude.Include.NON_NULL)
public String protocol;
}
}

+ 14
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/JobInfo.java View File

@@ -0,0 +1,14 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

public class JobInfo {
public String name;
public String stage;

@JsonProperty("project_id")
public String projectID;

@JsonProperty("project_name")
public String projectName;
}

+ 15
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/JobVariable.java View File

@@ -0,0 +1,15 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

public class JobVariable {
public String key;
public String value;
@JsonProperty("public")
public boolean isPublic;
@JsonProperty("-")
public boolean internal;
public boolean file;
public boolean masked;
public boolean raw;
}

+ 5
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/RunnerInfo.java View File

@@ -0,0 +1,5 @@
package tk.antoine_roux.wiki.model.response.secondary;

public class RunnerInfo {
public int timeout;
}

+ 33
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Secret.java View File

@@ -0,0 +1,33 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Map;

public class Secret {
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public VaultSecret vault;

public static class VaultSecret {
public VaultServer server;
public VaultEngine engine;
public String path;
public String field;
}

public static class VaultServer {
public String url;
public VaultAuth auth;
}

public static class VaultAuth {
public String name;
public String path;
public Map<String, Object> data;
}

public static class VaultEngine {
public String name;
public String path;
}
}

+ 14
- 0
src/main/java/tk/antoine_roux/wiki/model/response/secondary/Step.java View File

@@ -0,0 +1,14 @@
package tk.antoine_roux.wiki.model.response.secondary;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class Step {
public String name;
public List<String> script;
public int timeout;
public String when;
@JsonProperty("allow_failure")
public boolean allowFailure;
}

+ 75
- 0
src/main/java/tk/antoine_roux/wiki/service/GitService.java View File

@@ -0,0 +1,75 @@
package tk.antoine_roux.wiki.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import tk.antoine_roux.wiki.model.internal.GitlabCI;
import tk.antoine_roux.wiki.model.request.HookEvent;
import tk.antoine_roux.wiki.model.request.secondary.Commit;

import java.io.IOException;
import java.nio.file.Files;
import java.util.Optional;

@Service
public class GitService {

public static final String GITLAB_CI_FILE_PATH = ".gitlab-ci.yml";
private static final String GITLAB_RUNNER_CLONE_PREFIX = "gitlab-runner-clone";
public final UsernamePasswordCredentialsProvider credentialsProvider;
private final ObjectMapper objectMapper;

@Autowired
public GitService(UsernamePasswordCredentialsProvider credentialsProvider, @Qualifier("YAMLObjectMapper") ObjectMapper objectMapper) {
this.credentialsProvider = credentialsProvider;
this.objectMapper = objectMapper;
}

/**
* return .gitlab-ci.yml content for {@link HookEvent}
*/
public Optional<GitlabCI> getYMLGitlabCI(HookEvent hookEvent) throws IOException, GitAPIException {
Optional<GitlabCI> optJob;
if (hookEvent.commits.isEmpty()) {
optJob = Optional.empty();
} else {
// search for head commit or take first in event's list of commit
Commit commit = hookEvent.commits.stream().filter(co -> co.id.equals(hookEvent.headCommit))
.findFirst().orElse(hookEvent.commits.get(0));

optJob = Optional.of(this.getGitlabCIContent(hookEvent.repository.cloneUrl, commit));
}
return optJob;
}

/**
* return .gitlab-ci.yml content for given commit into cloneUrl repository
*/
private GitlabCI getGitlabCIContent(String cloneURL, Commit commit) throws IOException, GitAPIException {
Git call = Git.cloneRepository()
.setURI(cloneURL)
.setCredentialsProvider(this.credentialsProvider)
.setDirectory(Files.createTempDirectory(GITLAB_RUNNER_CLONE_PREFIX).toFile())
.call();

RevWalk revWalk = new RevWalk(call.getRepository());
RevCommit revCommit = revWalk.parseCommit(ObjectId.fromString(commit.id));

try (TreeWalk walk = TreeWalk.forPath(call.getRepository(), GITLAB_CI_FILE_PATH, revCommit.getTree())) {
if (walk != null) {
byte[] bytes = call.getRepository().open(walk.getObjectId(0)).getBytes();
return this.objectMapper.readValue(bytes, GitlabCI.class);
} else {
throw new IllegalArgumentException("No path found.");
}
}
}
}

+ 6
- 6
src/main/java/tk/antoine_roux/wiki/service/JobManager.java View File

@@ -1,9 +1,9 @@
package tk.antoine_roux.wiki.service;

import org.springframework.stereotype.Service;
import tk.antoine_roux.wiki.model.internal.HookEvent;
import tk.antoine_roux.wiki.model.internal.Job;
import tk.antoine_roux.wiki.model.request.JobRequest;
import tk.antoine_roux.wiki.model.request.HookEvent;
import tk.antoine_roux.wiki.model.response.JobResponse;

import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -12,16 +12,16 @@ import java.util.concurrent.ConcurrentLinkedQueue;
public class JobManager {

/**
* concurrent list of {@link Job} fill by {@link tk.antoine_roux.wiki.ControllerHandlers#webhook(HookEvent)}
* concurrent list of {@link JobResponse} fill by {@link tk.antoine_roux.wiki.ControllerHandlers#webhook(HookEvent)}
* and pop by {@link tk.antoine_roux.wiki.ControllerHandlers#jobRequest(JobRequest)}
*/
ConcurrentLinkedQueue<Job> jobQueue = new ConcurrentLinkedQueue<>();
ConcurrentLinkedQueue<JobResponse> jobQueue = new ConcurrentLinkedQueue<>();

public void stackJob(Job newJob) {
public void stackJob(JobResponse newJob) {
this.jobQueue.add(newJob);
}

public Optional<Job> popJob(JobRequest jobRequest) {
public Optional<JobResponse> popJob(JobRequest jobRequest) {
return Optional.ofNullable(this.jobQueue.poll());
}
}

+ 4
- 0
src/main/resources/application.properties View File

@@ -1,6 +1,7 @@
spring.main.banner-mode=off
spring.main.lazy-initialization=false
spring.output.ansi.enabled=ALWAYS
spring.jackson.serialization.write-dates-as-timestamps=false

server.port=^application.port^

@@ -17,3 +18,6 @@ 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

gitlab-ci.username=
gitlab-ci.password=

Loading…
Cancel
Save