jhipster-lite icon indicating copy to clipboard operation
jhipster-lite copied to clipboard

Add GraalVM support for JHipster Lite

Open jdubois opened this issue 2 years ago • 26 comments

  • fix https://github.com/jhipster/jhipster-lite/issues/2819

This adds GraalVM support to JHipster Lite.

To build the native image:

mvn -Pnative clean package spring-boot:build-image -DskipTests

To run it:

docker run -p 7471:7471 -it docker.io/library/jhlite:0.2.1-SNAPSHOT

What still needs to be done:

  • Eclipse JGit doesn't support GraalVM, so when the image runs, calling any JGit method will result in a stack trace. Quarkus has a JGit extension at https://github.com/quarkiverse/quarkus-jgit so this is possible to fix.

jdubois avatar Apr 26 '22 08:04 jdubois

@pascalgrimaud one important change: this removes Logback as it's not supported by Spring Native.

jdubois avatar Apr 26 '22 08:04 jdubois

Codecov Report

Merging #1483 (b1918b4) into main (bd16d9d) will not change coverage. The diff coverage is n/a.

@@             Coverage Diff             @@
##                main     #1483   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
  Complexity      1597      1597           
===========================================
  Files            305       305           
  Lines           5227      5227           
  Branches         106       106           
===========================================
  Hits            5227      5227           

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update bd16d9d...b1918b4. Read the comment docs.

codecov[bot] avatar Apr 26 '22 08:04 codecov[bot]

wow thanks @jdubois ! I'll try it soon

pascalgrimaud avatar Apr 26 '22 09:04 pascalgrimaud

@pascalgrimaud I added a GitHub Action step to automatically build the image, but it will only push it to GitHub packages if it's merged on the main branch. This is to limit the size this will take, as you need to pay for GitHub packages (the limit is pretty low). Maybe we should look at hosting this with Docker, JFrog, or Azure Container Registry.

jdubois avatar Apr 26 '22 09:04 jdubois

I built the image locally and indeed it started very very fast!

image

Inside the image, we need to install git, as some generation part needs to use git. Otherwise, we'll have this error:

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.Error: java.lang.NoSuchMethodException: org.eclipse.jgit.internal.JGitText.<init>()
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1082) ~[na:na]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[na:na]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[na:na]
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[na:na]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[na:na]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[na:na]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[na:na]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[na:na]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[na:na]
	at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) ~[na:na]

pascalgrimaud avatar Apr 27 '22 06:04 pascalgrimaud

@pascalgrimaud for Git: in fact you're using JGit, which is a Java library and it is not compatible with GraalVM by default. I'm having a look at fixing this, but this will take time and I will need help.

jdubois avatar Apr 28 '22 20:04 jdubois

Ok @jdubois : let me think if we can avoid using git, I'll investigate too

pascalgrimaud avatar Apr 28 '22 20:04 pascalgrimaud

I'm converting this PR to draft, until we find a solution for this :-)

pascalgrimaud avatar May 07 '22 05:05 pascalgrimaud

What do you think about recoding tech.jhipster.lite.generator.project.infrastructure.secondary.GitUtils and instead of using JGit (the Java implementation of Git that causes the issue), using an external command for Git like we do in tech.jhipster.lite.generator.packagemanager.npm.infrastructure.secondary.NpmLocalRepository (using the locally-installed version of NPM)? It's a little less portable, but if we consider that people need to have NPM installed, we can also consider they should have Git installed. And for cloud-based environments made with Docker, both shouldn't be an issue (we'll add them to the Docker image).

jdubois avatar Jun 16 '22 12:06 jdubois

Yes it's a valid solution, I'm fine with this :)

pascalgrimaud avatar Jun 16 '22 12:06 pascalgrimaud

@jdubois @pascalgrimaud I gave it a try as well, currently native image build fails for me. I do have a few suggestions though:

  • we probably can use GraalVM's GitHub action: https://github.com/marketplace/actions/github-action-for-graalvm
  • use native build tools: https://graalvm.github.io/native-build-tools/latest/index.html

alina-yur avatar Jul 08 '22 13:07 alina-yur

Thanks @alina-yur for trying this and for your suggestions

pascalgrimaud avatar Jul 08 '22 13:07 pascalgrimaud

The quarkus extensions looks quite small, it replaces the work queue and user home implementation (which seems to be the problematic parts, regarding the jgit issue tracker). I can check it, if we can just use the same substitutes in jhipster lite to make it work with graal without doing heavy refactoring or replacing jgit completly.

atomfrede avatar Jul 13 '22 06:07 atomfrede

@atomfrede : after discussing with @DamnClin I think we'll remove jgit. In fact we don't need it. It means we'll have this feature soon ;)

pascalgrimaud avatar Jul 13 '22 07:07 pascalgrimaud

@pascalgrimaud Awesome!

atomfrede avatar Jul 13 '22 07:07 atomfrede

After https://github.com/jhipster/jhipster-lite/pull/2469 we'll be left with 2 jgit usages:

  • In dummy feature -> we should totally rework this one (make it a module, generate different files, etc)
  • In init (for a git init), let's replace that by an exec (so that mean you'll need to install git on your servers)

DamnClin avatar Jul 13 '22 07:07 DamnClin

cc @jdubois, if you deploy the current main on a computer with git installed it won't using JGit anymore, hope that helps

DamnClin avatar Jul 21 '22 06:07 DamnClin

Thanks @DamnClin this is probably the easiest way to fix this!

jdubois avatar Jul 21 '22 09:07 jdubois

I gave a quick try this morning. Here different analysis:

I upgrade spring.native version to 0.12.1 Then, after building and running the image:

I got:

image

➜ docker run -it paketobuildpacks/builder:tiny git --version            
git version 2.17.1

But I think this image is used only for building, and git is not in the final image

I tried to use JGit from quarkus (the implem is secondary is unchanged), and I can't build the image:

diff --git a/pom.xml b/pom.xml
index 0983c82d0..0f012b938 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,7 +48,7 @@
     <jacoco.version>0.8.8</jacoco.version>
     <mustache.version>0.9.10</mustache.version>
     <guava.version>31.1-jre</guava.version>
-    <jgit.version>6.2.0.202206071550-r</jgit.version>
+    <quarkus-jgit.version>2.1.0</quarkus-jgit.version>
     <archunit-junit5.version>0.23.1</archunit-junit5.version>
     <springdoc-openapi-ui.version>1.6.9</springdoc-openapi-ui.version>
     <problem-spring.version>0.27.0</problem-spring.version>
@@ -104,9 +104,9 @@
       <version>${mustache.version}</version>
     </dependency>
     <dependency>
-      <groupId>org.eclipse.jgit</groupId>
-      <artifactId>org.eclipse.jgit</artifactId>
-      <version>${jgit.version}</version>
+      <groupId>io.quarkiverse.jgit</groupId>
+      <artifactId>quarkus-jgit</artifactId>
+      <version>${quarkus-jgit.version}</version>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>

image

So I added a new class to replace the JGitGitRepository:

class NoGitRepository implements GitRepository {

  private final Logger log = LoggerFactory.getLogger(NoGitRepository.class);

  @Override
  public void init(JHipsterProjectFolder folder) {
    log.info("Can't launch git init");
  }
}

After updating Bean configuration, I can start correctly the image. But there is a problem when using the "init" button:

image

This problem is not related to git but to something else. I didn't have time to investigate more

pascalgrimaud avatar Jul 23 '22 07:07 pascalgrimaud

For the command part this seems relevant https://github.com/oracle/graal/issues/1185

DamnClin avatar Jul 23 '22 07:07 DamnClin

Following these links:

  • https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/
  • https://github.com/spring-projects-experimental/spring-native/issues/1152

I manage to make it works

To fix the reflection, related to jackson :

@org.springframework.nativex.hint.TypeHint(
  types = { RestJHipsterModuleProperties.class, PersistedProjectHistory.class, ProjectHistory.class, ProjectDTO.class, PersistedProjectAction.class},
  access = { TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.PUBLIC_METHODS }
)

To fix the git configuration :

package tech.jhipster.lite.git.infrastructure.secondary;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.jhipster.lite.git.domain.GitCommitMessage;
import tech.jhipster.lite.git.domain.GitRepository;
import tech.jhipster.lite.module.domain.properties.JHipsterProjectFolder;

class NoGitRepository implements GitRepository {

  private final Logger log = LoggerFactory.getLogger(NoGitRepository.class);

  @Override
  public void init(JHipsterProjectFolder folder) {
    log.info("Can't launch git init");
  }

  @Override
  public void commitAll(JHipsterProjectFolder folder, GitCommitMessage message) {
    log.info("Can't launch git commit");
  }

  @Override
  public void commitAll(JHipsterProjectFolder folder, String message) {
    log.info("Can't launch git commit all");
  }
}

And GitRepositoryConfiguration :

@Configuration
class GitRepositoryConfiguration {

  private static final Logger log = LoggerFactory.getLogger(GitRepositoryConfiguration.class);

  @Value("${application.git:true}")
  private boolean applicationGit;

  @Bean
  GitRepository gitRepository(GitChecker checker) {
    if (!applicationGit) {
      log.info("Using No git repository");
      return new NoGitRepository();
    }

    if (checker.hasGit()) {
      log.info("Using command line git repository");
      return new CommandLineGitRepository();
    }

    log.info("Command line not available, using JGit git repository");
    return new JGitGitRepository();
  }
}

In application.properties :

application.git=true

Then to start Docker:

docker run -p 7471:7471 -it -e APPLICATION_GIT=false docker.io/library/jhlite:0.12.1-SNAPSHOT

pascalgrimaud avatar Jul 28 '22 14:07 pascalgrimaud

I don't understand. If we have to remove the git support then let's just delete the command line implementation. The whole goal of this was to be able to use it on graal, if it doesn't work let's just delete it!

BUT, removing git can't be done just like that, this is buggy since users will still have the commit checkbox on the frontend. I think we should either make git works (probably the easiest one to do) or to something to totally remove git options

DamnClin avatar Jul 28 '22 14:07 DamnClin

@DamnClin : no, I don't want to remove git, I just tried to make it works, that's all and as I didn't find a solution for Git in GraalVM image, I disabled it

pascalgrimaud avatar Jul 28 '22 14:07 pascalgrimaud

I can try the Quarkus like jgit replacement if you haven't done it already.

atomfrede avatar Jul 28 '22 14:07 atomfrede

@atomfrede : you can give a try, I already did it but it doesn't work

pascalgrimaud avatar Jul 28 '22 14:07 pascalgrimaud

Since the command line implementation for git manipulation wasn't helping (but still creating some logic duplication) I'm deleting it in https://github.com/jhipster/jhipster-lite/pull/3228

I think the plan for JGit isn't to use the quarkus dependency but to set this configuration in a spring native way: https://github.com/quarkiverse/quarkus-jgit/blob/main/deployment/src/main/java/io/quarkus/jgit/deployment/JGitProcessor.java

DamnClin avatar Aug 24 '22 13:08 DamnClin

Closing this, in favor of https://github.com/jhipster/jhipster-lite/pull/4314

pascalgrimaud avatar Nov 11 '22 18:11 pascalgrimaud

Oh maybe there can be some ideas which can be taken, specially for the build part cc @atomfrede

pascalgrimaud avatar Nov 11 '22 18:11 pascalgrimaud

Yes maybe we can (re)use the github actions configuration

atomfrede avatar Nov 11 '22 18:11 atomfrede