Initial commit
This commit is contained in:
commit
6b6a84977c
|
@ -0,0 +1,33 @@
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Woodpecker-Include
|
||||||
|
A microservice to be called from woodpecker to enable including pipeline configurations
|
|
@ -0,0 +1,32 @@
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
application
|
||||||
|
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "io.gitlab.jfronny"
|
||||||
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClass.set("io.gitlab.jfronny.woodpecker.include.Main")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://gitlab.com/api/v4/projects/35745143/packages/maven")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("net.freeutils:jlhttp:2.6")
|
||||||
|
implementation("com.amihaiemil.web:eo-yaml:6.1.0")
|
||||||
|
implementation("io.gitlab.jfronny:commons:2022.9.26+17-56-16")
|
||||||
|
implementation("io.gitlab.jfronny:commons-gson:2022.9.26+17-56-16")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.runShadow {
|
||||||
|
args("8002")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.compileJava {
|
||||||
|
options.compilerArgs.add("--enable-preview")
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = "woodpecker-include"
|
|
@ -0,0 +1,46 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.*;
|
||||||
|
import io.gitlab.jfronny.commons.HttpUtils;
|
||||||
|
import io.gitlab.jfronny.commons.serialize.Serializer;
|
||||||
|
import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders;
|
||||||
|
import io.gitlab.jfronny.woodpecker.include.model.*;
|
||||||
|
import io.gitlab.jfronny.woodpecker.include.util.YamlTypeAdapter;
|
||||||
|
import net.freeutils.httpserver.HTTPServer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
if (args.length != 1) {
|
||||||
|
System.err.println("Usage: woodpecker-include <port>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HTTPServer server = new HTTPServer(Integer.parseInt(args[0]));
|
||||||
|
HTTPServer.VirtualHost host = server.getVirtualHost(null);
|
||||||
|
GsonHolders.registerSerializer();
|
||||||
|
GsonHolders.registerTypeAdapter(YamlMapping.class, new YamlTypeAdapter());
|
||||||
|
HttpUtils.setUserAgent("Woodpecker-Include/1.0");
|
||||||
|
host.addContext("/ciconfig", (req, resp) -> {
|
||||||
|
try {
|
||||||
|
RequestModel request;
|
||||||
|
try (var isr = new InputStreamReader(req.getBody())) {
|
||||||
|
request = Serializer.getInstance().deserialize(isr, RequestModel.class);
|
||||||
|
}
|
||||||
|
AtomicBoolean changed = new AtomicBoolean(false);
|
||||||
|
ResponseModel response = new ResponseModel(request.configs.stream().mapMulti(new PipelineUnpacker(changed)).toList());
|
||||||
|
if (changed.get()) {
|
||||||
|
try (OutputStreamWriter writer = new OutputStreamWriter(resp.getBody())) {
|
||||||
|
Serializer.getInstance().serialize(response, writer);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else return 204;
|
||||||
|
} catch (UncheckedIOException e) {
|
||||||
|
throw e.getCause();
|
||||||
|
}
|
||||||
|
}, "POST");
|
||||||
|
server.start();
|
||||||
|
System.out.println("Running Woodpecker-Include");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.*;
|
||||||
|
import io.gitlab.jfronny.commons.HttpUtils;
|
||||||
|
import io.gitlab.jfronny.woodpecker.include.model.Pipeline;
|
||||||
|
import io.gitlab.jfronny.woodpecker.include.util.FilteringYamlMapping;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
record PipelineUnpacker(AtomicBoolean changed) implements BiConsumer<Pipeline, Consumer<Pipeline>> {
|
||||||
|
@Override
|
||||||
|
public void accept(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer) {
|
||||||
|
try {
|
||||||
|
processPipeline(pipeline, pipelineConsumer);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new UncheckedIOException(new IOException("Could not find URL", e));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPipeline(Pipeline pipeline, Consumer<Pipeline> pipelineConsumer) throws URISyntaxException, IOException {
|
||||||
|
YamlNode include = pipeline.data.value("include");
|
||||||
|
if (include == null) {
|
||||||
|
// Has no includes
|
||||||
|
pipelineConsumer.accept(pipeline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
changed.set(true);
|
||||||
|
// Send included
|
||||||
|
switch (include) {
|
||||||
|
case Scalar str -> download(str.value(), null, pipelineConsumer);
|
||||||
|
case YamlMapping map -> {
|
||||||
|
for (YamlNode key : map.keys()) {
|
||||||
|
download(map.string(key), key.asScalar().value(), pipelineConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case YamlSequence seq -> {
|
||||||
|
for (YamlNode node : seq) {
|
||||||
|
download(node.asScalar().value(), null, pipelineConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + include);
|
||||||
|
}
|
||||||
|
// Remove include from original
|
||||||
|
Pipeline filtered = new Pipeline();
|
||||||
|
filtered.name = pipeline.name;
|
||||||
|
pipeline.data = new FilteringYamlMapping(pipeline.data, s -> !s.asScalar().value().equals("include"));
|
||||||
|
pipelineConsumer.accept(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void download(String url, String fileName, Consumer<Pipeline> pipelineConsumer) throws URISyntaxException, IOException {
|
||||||
|
URI uri = new URI(url.replace(" ", "%20"));
|
||||||
|
if (!"http".equalsIgnoreCase(uri.getScheme()) && !"https".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
throw new URISyntaxException(url, "Could not find scheme");
|
||||||
|
}
|
||||||
|
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
|
||||||
|
Pipeline pipeline = new Pipeline();
|
||||||
|
pipeline.name = fileName != null ? fileName : Paths.get(new URI(url.replace(" ", "%20")).getPath()).getFileName().toString();
|
||||||
|
pipeline.data = Yaml.createYamlInput(is).readYamlMapping();
|
||||||
|
processPipeline(pipeline, pipelineConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Build {
|
||||||
|
public String author;
|
||||||
|
public String author_avatar;
|
||||||
|
public String author_email;
|
||||||
|
public String branch;
|
||||||
|
public List<String> changed_files;
|
||||||
|
public String commit;
|
||||||
|
public Long created_at;
|
||||||
|
public String deploy_to;
|
||||||
|
public Long enqueued_at;
|
||||||
|
public String error;
|
||||||
|
public String event;
|
||||||
|
public Long finished_at;
|
||||||
|
public Long id;
|
||||||
|
public String link_url;
|
||||||
|
public String message;
|
||||||
|
public Long number;
|
||||||
|
public Long parent;
|
||||||
|
public String ref;
|
||||||
|
public String refspec;
|
||||||
|
public String remote;
|
||||||
|
public Long reviewed_at;
|
||||||
|
public String reviewed_by;
|
||||||
|
public String sender;
|
||||||
|
public Boolean signed;
|
||||||
|
public Long started_at;
|
||||||
|
public String status;
|
||||||
|
public Long timestamp;
|
||||||
|
public String title;
|
||||||
|
public Long updated_at;
|
||||||
|
public Boolean verified;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
|
|
||||||
|
public class Pipeline {
|
||||||
|
public String name;
|
||||||
|
public YamlMapping data;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import io.gitlab.jfronny.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Repo {
|
||||||
|
public Long id;
|
||||||
|
public String uid;
|
||||||
|
public Long user_id;
|
||||||
|
public String namespace;
|
||||||
|
public String name;
|
||||||
|
public String slug;
|
||||||
|
public String scm;
|
||||||
|
public String git_http_url;
|
||||||
|
public String git_ssh_url;
|
||||||
|
public String link;
|
||||||
|
public String default_branch;
|
||||||
|
@SerializedName("private")
|
||||||
|
public Boolean private$;
|
||||||
|
public String visibility;
|
||||||
|
public Boolean active;
|
||||||
|
public String config;
|
||||||
|
public Boolean trusted;
|
||||||
|
@SerializedName("protected")
|
||||||
|
public Boolean protected$;
|
||||||
|
public Boolean ignore_forks;
|
||||||
|
public Boolean ignore_pulls;
|
||||||
|
public Boolean cancel_pulls;
|
||||||
|
public Long timeout;
|
||||||
|
public Long counter;
|
||||||
|
public Long synced;
|
||||||
|
public Long created;
|
||||||
|
public Long updated;
|
||||||
|
public Long version;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RequestModel {
|
||||||
|
public Repo repo;
|
||||||
|
public Build build;
|
||||||
|
public List<Pipeline> configs;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ResponseModel {
|
||||||
|
public List<Pipeline> configs;
|
||||||
|
|
||||||
|
public ResponseModel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseModel(List<Pipeline> configs) {
|
||||||
|
this.configs = List.copyOf(configs);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.util;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class FilteringYamlMapping extends BaseYamlMapping {
|
||||||
|
private final YamlMapping base;
|
||||||
|
private final Predicate<YamlNode> filter;
|
||||||
|
|
||||||
|
public FilteringYamlMapping(YamlMapping base, Predicate<YamlNode> filter) {
|
||||||
|
this.base = base;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<YamlNode> keys() {
|
||||||
|
return base.keys().stream().filter(filter).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YamlNode value(YamlNode key) {
|
||||||
|
return filter.test(key) ? base.value(key) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comment comment() {
|
||||||
|
return base.comment();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package io.gitlab.jfronny.woodpecker.include.util;
|
||||||
|
|
||||||
|
import com.amihaiemil.eoyaml.Yaml;
|
||||||
|
import com.amihaiemil.eoyaml.YamlMapping;
|
||||||
|
import io.gitlab.jfronny.gson.TypeAdapter;
|
||||||
|
import io.gitlab.jfronny.gson.stream.JsonReader;
|
||||||
|
import io.gitlab.jfronny.gson.stream.JsonWriter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class YamlTypeAdapter extends TypeAdapter<YamlMapping> {
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter jsonWriter, YamlMapping yamlMapping) throws IOException {
|
||||||
|
jsonWriter.value(yamlMapping.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public YamlMapping read(JsonReader jsonReader) throws IOException {
|
||||||
|
return Yaml.createYamlInput(jsonReader.nextString()).readYamlMapping();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue