Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit to add a GIT config source #152

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
release.properties

# Quarkus
.quarkus

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ These extensions allows reading the Quarkus configuration properties from variou
* [HashiCorp Consul](https://www.consul.io)
* HOCON
* [Jasypt](http://www.jasypt.org)
* [Git](https://github.com/quarkiverse/quarkus-jgit)

## Documentation

Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
* xref:consul.adoc[HashiCorp Consul]
* xref:jdbc.adoc[JDBC Config]
* xref:jasypt.adoc[Jasypt]
* xref:git.adoc[GIT Config]
132 changes: 132 additions & 0 deletions docs/modules/ROOT/pages/git.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
= Quarkus GIT Config

include::./includes/attributes.adoc[]

This guide explains how your Quarkus application can read configuration properties from a GIT repository.

== Prerequisites

To complete this guide, you need:

* less than 15 minutes
* an IDE
* JDK 11+ installed with `JAVA_HOME` configured appropriately
* Apache Maven {maven-version}


== Solution

We recommend that you follow the instructions in the next sections and create the application step by step.

== Introduction

TODO

== Creating the Maven project

First, we need a new project. Create a new project with the following command:

[source,bash,subs=attributes+]
----
mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=config-git-quickstart \
-DclassName="org.acme.git.config.GreetingResource" \
-Dpath="/greeting" \
-Dextensions="config-git"
cd config-git-quickstart
----

This command generates a Maven project with a REST endpoint and imports the `config-git` extension.

If you already have your Quarkus project configured, you can add the `config-git` extension
to your project by running the following command in your project base directory:

[source,bash]
----
./mvnw quarkus:add-extension -Dextensions="config-git"
----

This will add the following to your `pom.xml`:

[source,xml,subs=attributes+]
----
<dependency>
<groupId>io.quarkiverse.config</groupId>
<artifactId>quarkus-config-git</artifactId>
<version>{quarkus-config-extensions-version}</version>
</dependency>
----

== GreetingController

The Quarkus Maven plugin automatically generated a `GreetingResource` JAX-RS resource in the
`src/main/java/org/acme/consul/config/client/GreetingResource.java` file that looks like:

[source,java]
----
package org.acme.consul.config.client;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/greeting")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
----

As we want to use configuration properties obtained from the Config Server, we will update the `GreetingResource` to inject the `message` property. The updated code will look like this:

[source,java]
----
package org.acme.consul.config.client;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@Path("/greeting")
public class GreetingResource {
@ConfigProperty(name = "greeting.message", defaultValue="Hello from default")
String message;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return message;
}
}
----

== Configuring the application

Quarkus provides various configuration knobs under the `quarkus.git-config-source` root. For the purposes of this guide, our Quarkus application is going to be configured in `application.properties` as follows:

[source,properties]
----
quarkus.git-config-source.TODO
----

== Create a versioned property file

TODO


== Package and run the application

Run the application with: `./mvnw compile quarkus:dev`.
Open your browser to http://localhost:8080/greeting.

The result should be: `Hello from GIT` as it is the value obtained from the database.

== Run the application as a native executable

You can of course create a native image using the instructions of the link:building-native-image[Building a native executable guide].

== Configuration Reference

include::./includes/quarkus-git-config.adoc[]
32 changes: 32 additions & 0 deletions docs/modules/ROOT/pages/includes/quarkus-git-config.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[.configuration-legend]
icon:lock[title=Fixed at build time] Configuration property fixed at build time - All other configuration properties are overridable at runtime
[.configuration-reference.searchable, cols="80,.^10,.^10"]
|===

h|[[quarkus-git-config_configuration]]link:#quarkus-git-config_configuration[Configuration property]

h|Type
h|Default

a| [[quarkus-git-config_quarkus.git-config-source.TODO]]`link:#quarkus-git-config_quarkus.git-config-source.TODO[quarkus.git-config-source.TODO]`

[.description]
--
If set to true, the application will attempt to look up the configuration from a GIT repository
--|boolean
|`true`

|===
ifndef::no-duration-note[]
[NOTE]
[[duration-note-anchor]]
.About the Duration format
====
The format for durations uses the standard `java.time.Duration` format.
You can learn more about it in the link:https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-[Duration#parse() javadoc].

You can also provide duration values starting with a number.
In this case, if the value consists only of a number, the converter treats the value as seconds.
Otherwise, `PT` is implicitly prepended to the value to obtain a standard `java.time.Duration` format.
====
endif::no-duration-note[]
54 changes: 54 additions & 0 deletions git/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkiverse.config</groupId>
<artifactId>quarkus-config-git-parent</artifactId>
<version>2.1.1-SNAPSHOT</version>
</parent>
<artifactId>quarkus-config-git-deployment</artifactId>
<name>Quarkus - Config Extensions - GIT - Deployment</name>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.config</groupId>
<artifactId>quarkus-config-git</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkiverse.jgit</groupId>
<artifactId>quarkus-jgit-deployment</artifactId>
<version>${quarkus.jgit.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkiverse.quarkus.git.config.deployment;

import io.quarkiverse.quarkus.git.config.runtime.GitConfigBuilder;
import io.quarkiverse.quarkus.git.config.runtime.config.GitConfigSourceConfiguration;
import io.quarkiverse.quarkus.git.config.runtime.deployment.GitConfigSourceRecorder;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;

class GitConfigSourceProcessor {

private static final String FEATURE = GitConfigSourceConfiguration.EXTENSION_NAME;

@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

@BuildStep
RunTimeConfigBuilderBuildItem configSource() {
return new RunTimeConfigBuilderBuildItem(GitConfigBuilder.class);
}

@BuildStep
@Record(value = ExecutionTime.RUNTIME_INIT)
void initGitSource(GitConfigSourceRecorder recorder, GitConfigSourceConfiguration configuration) {
recorder.init(configuration);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.quarkiverse.quarkus.git.config.test;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;

import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkiverse.quarkus.git.config.test.resources.GitRepository;
import io.quarkus.test.QuarkusUnitTest;

public class GitFilenameOverrideConfigSourceTest {

private static final String TEST_NAME = "filename";

public static final Path TEST_REPO_ROOT = Path.of("/tmp/git-config-source/tests");

private static final Runnable BEFORE_ALL = () -> {
var repoPath = TEST_REPO_ROOT.resolve(TEST_NAME);
GitRepository.free(repoPath);
try {
Files.createDirectories(repoPath);
var sourceURL = Thread.currentThread().getContextClassLoader()
.getResource("remote-filename-application.properties");
GitRepository.of(repoPath).init().addFile(new File(sourceURL.toURI()), "filename_override.properties");
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}
};

// Start unit test with your extension loaded
@RegisterExtension
static final QuarkusUnitTest unitTest = new QuarkusUnitTest()
.withConfigurationResource(TEST_NAME + "-application.properties")
.setBeforeAllCustomizer(BEFORE_ALL)
.setArchiveProducer(() -> {
return ShrinkWrap.create(JavaArchive.class)
.addClass(GitRepository.class)
.addAsResource("remote-application.properties");
});

@AfterAll
public static void afterAll() throws IOException {
Path repoPath = TEST_REPO_ROOT.resolve(TEST_NAME);
GitRepository.free(repoPath);
}

@Test
public void testTheConfigValue() {
var cfg = ConfigProvider.getConfig().getOptionalValue("a.test.key", String.class);
assertThat(cfg).isNotEmpty().contains("a test integration value from another place");
}
}
Loading
Loading