5
5
import dev .jeka .core .api .project .JkIdeSupport ;
6
6
import dev .jeka .core .api .project .JkIdeSupportSupplier ;
7
7
import dev .jeka .core .api .project .JkProject ;
8
+ import dev .jeka .core .api .system .JkLog ;
9
+ import dev .jeka .core .api .testing .ApplicationTester ;
10
+ import dev .jeka .core .api .testing .JkTestProcessor ;
11
+ import dev .jeka .core .api .testing .JkTestSelection ;
12
+ import dev .jeka .core .api .tooling .docker .JkDocker ;
13
+ import dev .jeka .core .api .tooling .docker .JkDockerBuild ;
14
+ import dev .jeka .core .api .tooling .docker .JkDockerJvmBuild ;
15
+ import dev .jeka .core .api .utils .JkUtilsNet ;
8
16
import dev .jeka .core .tool .JkDoc ;
9
17
import dev .jeka .core .tool .JkInjectProperty ;
10
18
import dev .jeka .core .tool .KBean ;
16
24
import java .nio .file .Files ;
17
25
import java .nio .file .Path ;
18
26
import java .util .List ;
27
+ import java .util .Optional ;
19
28
20
29
@ JkDoc ("""
21
30
Builds a Spring-Boot project, optionally containing a reactjs frontend.
@@ -38,25 +47,51 @@ public class SpringBootTemplateBuild extends KBean implements JkIdeSupportSuppli
38
47
39
48
public static final String REACTJS_BASE_DIR = "reactjs-client" ;
40
49
50
+ static final String E2E_TEST_PATTERN = "^e2e\\ ..*" ;
51
+
41
52
// Do not enforce to use a specific of NodeJs. Propose latest LTS versions instead.
42
53
@ JkDepSuggest (versionOnly = true , hint = "20.10.0,18.19.0,16.20.2" )
43
54
public String nodeJsVersion = NODEJS_VERSION ;
44
55
45
- @ JkDoc ("The unique application id within the organization. By defauly values to root dir name." )
56
+ @ JkDoc ("The unique application id within the organization. By default, it values to the root dir name." )
46
57
public String appId = getBaseDir ().toAbsolutePath ().getFileName ().toString ();
47
58
48
59
@ JkDoc ("Project version injected by CI/CD tool" )
49
60
@ JkInjectProperty ("PROJECT_VERSION" )
50
61
private String projectVersion ;
51
62
63
+ private JkProject project = JkProject .of ();
64
+
65
+ @ Override
66
+ protected void init () {
67
+ project .setModuleId (appId );
68
+ project .setVersion (projectVersion );
69
+ project .packaging .getManifest ().addMainAttribute (JkManifest .IMPLEMENTATION_VERSION , projectVersion );
70
+ project .testing .testSelection .addExcludePatterns (E2E_TEST_PATTERN );
71
+
72
+ // Configure project as a Spring-Boot application
73
+ JkSpringbootProject .of (project ).configure ();
74
+
75
+ // Build reactJs if 'reactjs-client' dir is present.
76
+ // The bundled js app is copied in 'resources/static'.
77
+ if (Files .exists (reactBaseDir ())) {
78
+ JkNodeJs .ofVersion (nodeJsVersion ).configure (
79
+ project ,
80
+ REACTJS_BASE_DIR ,
81
+ "build" ,
82
+ "static" ,
83
+ List .of ("npx yarn install " , "npm run build" ),
84
+ List .of ());
85
+ }
86
+ }
87
+
52
88
@ JkDoc ("Performs a simple build, without code coverage" )
53
89
public void pack () {
54
- project () .clean ().pack ();
90
+ project .clean ().pack ();
55
91
}
56
92
57
93
@ JkDoc ("Performs a build including quality static analysis." )
58
94
public void packQuality () {
59
- JkProject project = project ();
60
95
JkJacoco .ofVersion (getRunbase ().getDependencyResolver (), JACOCO_VERSION )
61
96
.configureFor (project );
62
97
project .clean ().pack ();
@@ -83,48 +118,97 @@ public void packQuality() {
83
118
84
119
@ JkDoc ("Executes the built bootable jar" )
85
120
public void runJar () {
86
- project () .prepareRunJar (JkProject .RuntimeDeps .EXCLUDE ).run ();
121
+ project .prepareRunJar (JkProject .RuntimeDeps .EXCLUDE ).run ();
87
122
}
88
123
89
124
@ JkDoc ("Displays the dependency tree on the console." )
90
125
public void depTree () {
91
- project () .displayDependencyTree ();
126
+ project .displayDependencyTree ();
92
127
}
93
128
94
- @ Override
95
- public JkIdeSupport getJavaIdeSupport () {
96
- return project ().getJavaIdeSupport ();
129
+ @ JkDoc ("Creates a Docker image of the application" )
130
+ public void buildImage () {
131
+ JkDockerJvmBuild .of (project )
132
+ .setExposedPorts (8080 )
133
+ .buildImage (imageName ());
97
134
}
98
135
99
- private JkProject project () {
100
- JkProject project = JkProject .of ();
101
- project .setModuleId (appId );
102
- project .setVersion (projectVersion );
103
- project .packaging .getManifest ().addMainAttribute (JkManifest .IMPLEMENTATION_VERSION , projectVersion );
104
-
105
- // Configure project as a Spring-Boot application
106
- JkSpringbootProject .of (project ).configure ();
136
+ @ JkDoc ("Run the Docker image and execute E2E tests (browser based)" )
137
+ public void runE2e () {
138
+ new DockerTester ().run ();
139
+ }
107
140
108
- // Build reactJs if 'reactjs-client' dir is present.
109
- // The bundled js app is copied in 'resources/static'.
110
- if (Files .exists (reactBaseDir ())) {
111
- JkNodeJs .ofVersion (nodeJsVersion ).configure (
112
- project ,
113
- REACTJS_BASE_DIR ,
114
- "build" ,
115
- "static" ,
116
- List .of ("npx yarn install " , "npm run build" ),
117
- List .of ());
118
- }
119
- return project ;
141
+ @ Override
142
+ public JkIdeSupport getJavaIdeSupport () {
143
+ return project .getJavaIdeSupport ();
120
144
}
121
145
122
146
private Path reactBaseDir () {
123
147
return getBaseDir ().resolve (REACTJS_BASE_DIR );
124
148
}
125
149
150
+ private String imageName () {
151
+ String version = Optional .ofNullable (projectVersion ).orElse ("latest" );
152
+ return "my-org/" + appId + ":" + version ;
153
+ }
154
+
155
+
126
156
private JkSonarqube sonarqubeBase () {
127
157
return JkSonarqube .ofVersion (getRunbase ().getDependencyResolver (), SONARQUBE_VERSION );
128
158
}
129
159
160
+ private void execSelenideTests (String baseUrl ) {
161
+ //project.compilation.runIfNeeded();
162
+ //project.testing.compilation.runIfNeeded();
163
+ JkTestSelection selection = project .testing .createDefaultTestSelection ()
164
+ .addIncludePatterns (E2E_TEST_PATTERN );
165
+ JkTestProcessor testProcessor = project .testing .createDefaultTestProcessor ().setForkingProcess (true );
166
+ testProcessor .getForkingProcess ()
167
+ .setLogWithJekaDecorator (true )
168
+ .setLogCommand (true )
169
+ .addJavaOptions ("-Dselenide.reportsFolder=jeka-output/test-report/selenide" )
170
+ .addJavaOptions ("-Dselenide.downloadsFolder=jeka-output/test-report/selenide-download" )
171
+ .addJavaOptions ("-Dselenide.headless=true" )
172
+ .addJavaOptions ("-Dselenide.baseUrl=" + baseUrl );
173
+ testProcessor .launch (project .testing .getTestClasspath (), selection ).assertSuccess ();
174
+ }
175
+
176
+ class DockerTester extends ApplicationTester {
177
+
178
+ int port ;
179
+
180
+ String baseUrl ;
181
+
182
+ String containerName ;
183
+
184
+ @ Override
185
+ protected void startApp () {
186
+ port = findFreePort ();
187
+ baseUrl = "http://localhost:" + port ;
188
+ containerName = project .getBaseDir ().toAbsolutePath ().getFileName ().toString () + "-" + port ;
189
+ JkDocker .prepareExec ("run" , "-d" , "-p" , String .format ("%s:8080" , port ), "--name" ,
190
+ containerName , SpringBootTemplateBuild .this .imageName ())
191
+ .setInheritIO (false )
192
+ .setLogWithJekaDecorator (true )
193
+ .exec ();
194
+ }
195
+
196
+ @ Override
197
+ protected boolean isApplicationReady () {
198
+ return JkUtilsNet .isAvailableAndOk (baseUrl , JkLog .isDebug ());
199
+ }
200
+
201
+ @ Override
202
+ protected void executeTests () {
203
+ execSelenideTests (baseUrl );
204
+ }
205
+
206
+ @ Override
207
+ protected void stopGracefully () {
208
+ JkDocker .prepareExec ("rm" , "-f" , containerName )
209
+ .setInheritIO (false ).setLogWithJekaDecorator (true )
210
+ .exec ();
211
+ }
212
+ }
213
+
130
214
}
0 commit comments