Skip to content

Commit

Permalink
Backend: Add simple CI based on groovy dsl
Browse files Browse the repository at this point in the history
  • Loading branch information
MWGuy committed Dec 19, 2020
1 parent c6c98cc commit 5d9b94d
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 25 deletions.
14 changes: 14 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'org.springframework.boot' version '2.4.0'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
id 'groovy'
}

repositories {
Expand All @@ -14,13 +15,26 @@ configurations {
}
}

sourceSets {
main {
groovy {
srcDirs = ['src/main/groovy', 'src/main/java']
}
java {
srcDirs = []
}
}
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:8.0.0'
implementation 'com.graphql-java-kickstart:playground-spring-boot-starter:8.0.0'
implementation 'org.codehaus.groovy:groovy-all:3.0.7'
implementation 'commons-io:commons-io:2.6'

implementation project(':git-cli')

Expand Down
11 changes: 11 additions & 0 deletions backend/src/main/groovy/com/mwguy/vgit/ci/dsl/CI.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mwguy.vgit.ci.dsl

class CI {
public Pipeline pipeline

void pipeline(@DelegatesTo(value = Pipeline) Closure closure) {
closure.resolveStrategy = Closure.DELEGATE_ONLY
closure.delegate = pipeline = new Pipeline()
closure.call()
}
}
9 changes: 9 additions & 0 deletions backend/src/main/groovy/com/mwguy/vgit/ci/dsl/Job.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.mwguy.vgit.ci.dsl

class Job {
public List<String> commands = []

void sh(String command) {
commands << command
}
}
21 changes: 21 additions & 0 deletions backend/src/main/groovy/com/mwguy/vgit/ci/dsl/Pipeline.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.mwguy.vgit.ci.dsl

import groovy.transform.NamedParam

class Pipeline {
public Map<String, String> environment = [:]
public Map<String, Stage> stages = [:]

void environment(@DelegatesTo(Map) Closure closure) {
environment.with(closure)
}

void stage(@NamedParam("name") String name, @DelegatesTo(Stage) Closure closure) {
def stage = new Stage();
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.delegate = stage
closure.call()

stages.put(name, stage)
}
}
17 changes: 17 additions & 0 deletions backend/src/main/groovy/com/mwguy/vgit/ci/dsl/Stage.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mwguy.vgit.ci.dsl

import groovy.transform.NamedParam

class Stage {
public Map<String, Job> jobs = [:]

void job(@NamedParam("name") String name, @DelegatesTo(Job) Closure closure) {
def job = new Job();

closure.delegate = job
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure.call()

jobs.put(name, job)
}
}
47 changes: 33 additions & 14 deletions backend/src/main/java/com/mwguy/vgit/controllers/GitController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.mwguy.vgit.data.GitCommit;
import com.mwguy.vgit.data.GitPackType;
import com.mwguy.vgit.exceptions.GitException;
import com.mwguy.vgit.service.CIService;
import com.mwguy.vgit.service.GitService;
import com.mwguy.vgit.service.HooksService;
import com.mwguy.vgit.service.RepositoriesService;
Expand All @@ -15,18 +16,22 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@RestController
public class GitController {
private final CIService ciService;
private final GitService gitService;
private final RepositoriesService repositoriesService;
private final HooksService hooksService;
private final TaskExecutor taskExecutor;

public GitController(GitService gitService, RepositoriesService repositoriesService, HooksService hooksService, TaskExecutor taskExecutor) {
public GitController(CIService ciService, GitService gitService, RepositoriesService repositoriesService, HooksService hooksService, TaskExecutor taskExecutor) {
this.ciService = ciService;
this.gitService = gitService;
this.repositoriesService = repositoriesService;
this.hooksService = hooksService;
Expand Down Expand Up @@ -82,11 +87,11 @@ public void hookType(
@PathVariable("path") String path,
@PathVariable("type") String type,
HttpEntity<String> httpEntity
) throws IOException, InterruptedException {
) {
RepositoryDao repositoryDao = repositoriesService
.findRepositoryAndCheckPermissions(namespace, path, RepositoryDao.PermissionType.HOOK_TRIGGER);

if (!hooksService.hasHooks(repositoryDao, RepositoryDao.RepositoryHookType.PUSH)) {
if (!"POST_RECEIVE".equals(type)) {
return;
}

Expand All @@ -96,18 +101,32 @@ public void hookType(
String newTree = input[1];
String branch = input[2];

if (hooksService.hasHooks(repositoryDao, RepositoryDao.RepositoryHookType.GIT_PUSH)) {
try {
List<GitCommit> commits = gitService.getGit()
.log()
.repository(repositoryDao.toGitRepository())
.branch(branch)
.oldTree(oldTree)
.newTree(newTree)
.build()
.call();

hooksService.asyncTriggerWebHooks(repositoryDao, RepositoryDao.RepositoryHookType.GIT_PUSH, commits);
} catch (GitException e) {
e.printStackTrace();
}
}

try {
List<GitCommit> commits = gitService.getGit()
.log()
.repository(repositoryDao.toGitRepository())
.branch(branch)
.oldTree(oldTree)
.newTree(newTree)
.build()
.call();

hooksService.triggerHook(repositoryDao, RepositoryDao.RepositoryHookType.PUSH, commits);
} catch (GitException e) {
Optional<InputStream> pipelineInputStream = ciService.findPipelineScript(newTree, repositoryDao);
if (pipelineInputStream.isEmpty()) {
return;
}

log.info("Found '.pipeline.groovy' file, executing ci...");
ciService.runGroovyPipeline(repositoryDao, pipelineInputStream.get());
} catch (Exception e) {
e.printStackTrace();
}
});
Expand Down
19 changes: 13 additions & 6 deletions backend/src/main/java/com/mwguy/vgit/dao/RepositoryDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
Expand Down Expand Up @@ -54,7 +55,10 @@ public enum RepositoryPathType {
}

public enum RepositoryHookType {
PUSH
GIT_PUSH,

PIPELINE_FAILED,
PIPELINE_PASSED
}

@Getter
Expand All @@ -81,7 +85,7 @@ public static class RepositoryHookRequestLogEntity {
@NoArgsConstructor
@AllArgsConstructor
public static class RepositoryHook {
private RepositoryHookType type;
private Set<RepositoryHookType> types;
private URL url;
private Set<RepositoryHookRequestLogEntity> requestLog;
}
Expand Down Expand Up @@ -156,6 +160,7 @@ public static class PaginationInput {
}

@Data
@Builder
public static class GitTreeInput {
private String path;
private String object;
Expand All @@ -182,14 +187,16 @@ public List<GitTreeEntry> getTree(GitTreeInput input) throws GitException {
}

public String getBlob(String object) throws GitException, IOException {
return Base64.encodeBase64String(getBlobAsInputStream(object).readAllBytes());
}

public InputStream getBlobAsInputStream(String object) throws GitException {
Git git = VGitApplication.context.getBean(Git.class);
return Base64.encodeBase64String(git.catFile()
return git.catFile()
.repository(toGitRepository())
.type(GitTreeEntry.GitObjectType.BLOB)
.object(object)
.build()
.call()
.readAllBytes()
);
.call();
}
}
Loading

0 comments on commit 5d9b94d

Please sign in to comment.