mirror of
https://gitee.com/dcren/initializr.git
synced 2025-12-21 19:10:00 +08:00
Use bullet list for compose services
Closes gh-1419
This commit is contained in:
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
package io.spring.initializr.generator.spring.container.docker.compose;
|
package io.spring.initializr.generator.spring.container.docker.compose;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import io.spring.initializr.generator.container.docker.compose.ComposeFile;
|
import io.spring.initializr.generator.container.docker.compose.ComposeFile;
|
||||||
import io.spring.initializr.generator.container.docker.compose.ComposeService;
|
import io.spring.initializr.generator.container.docker.compose.ComposeService;
|
||||||
import io.spring.initializr.generator.spring.container.docker.compose.Markdown.MarkdownTable;
|
|
||||||
import io.spring.initializr.generator.spring.documentation.HelpDocument;
|
import io.spring.initializr.generator.spring.documentation.HelpDocument;
|
||||||
import io.spring.initializr.generator.spring.documentation.HelpDocumentCustomizer;
|
import io.spring.initializr.generator.spring.documentation.HelpDocumentCustomizer;
|
||||||
|
|
||||||
@@ -31,11 +31,11 @@ import io.spring.initializr.generator.spring.documentation.HelpDocumentCustomize
|
|||||||
*
|
*
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
public class DockerComposeHelpDocumentCustomizer implements HelpDocumentCustomizer {
|
public class ComposeHelpDocumentCustomizer implements HelpDocumentCustomizer {
|
||||||
|
|
||||||
private final ComposeFile composeFile;
|
private final ComposeFile composeFile;
|
||||||
|
|
||||||
public DockerComposeHelpDocumentCustomizer(ComposeFile composeFile) {
|
public ComposeHelpDocumentCustomizer(ComposeFile composeFile) {
|
||||||
this.composeFile = composeFile;
|
this.composeFile = composeFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,18 +43,16 @@ public class DockerComposeHelpDocumentCustomizer implements HelpDocumentCustomiz
|
|||||||
public void customize(HelpDocument document) {
|
public void customize(HelpDocument document) {
|
||||||
Map<String, Object> model = new HashMap<>();
|
Map<String, Object> model = new HashMap<>();
|
||||||
if (this.composeFile.services().isEmpty()) {
|
if (this.composeFile.services().isEmpty()) {
|
||||||
model.put("serviceTable", null);
|
|
||||||
document.getWarnings()
|
document.getWarnings()
|
||||||
.addItem(
|
.addItem(
|
||||||
"No Docker Compose services found. As of now, the application won't start! Please add at least one service to the `compose.yaml` file.");
|
"No Docker Compose services found. As of now, the application won't start! Please add at least one service to the `compose.yaml` file.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MarkdownTable serviceTable = Markdown.table("Service name", "Image", "Tag", "Website");
|
model.put("services",
|
||||||
this.composeFile.services()
|
this.composeFile.services()
|
||||||
.values()
|
.values()
|
||||||
.forEach((service) -> serviceTable.addRow(service.getName(), Markdown.code(service.getImage()),
|
.sorted(Comparator.comparing(ComposeService::getName))
|
||||||
Markdown.code(service.getImageTag()), Markdown.link("Website", service.getImageWebsite())));
|
.toList());
|
||||||
model.put("serviceTable", serviceTable.toMarkdown());
|
|
||||||
}
|
}
|
||||||
document.addSection("documentation/docker-compose", model);
|
document.addSection("documentation/docker-compose", model);
|
||||||
}
|
}
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2023 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.spring.initializr.generator.spring.container.docker.compose;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class for Markdown.
|
|
||||||
*
|
|
||||||
* @author Moritz Halbritter
|
|
||||||
*/
|
|
||||||
final class Markdown {
|
|
||||||
|
|
||||||
private Markdown() {
|
|
||||||
// Static class
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the given string as code.
|
|
||||||
* @param code the input string
|
|
||||||
* @return string formatted as code
|
|
||||||
*/
|
|
||||||
static String code(String code) {
|
|
||||||
return "`%s`".formatted(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Markdown link.
|
|
||||||
* @param text text of the link
|
|
||||||
* @param url url of the link
|
|
||||||
* @return the formatted link in Markdown
|
|
||||||
*/
|
|
||||||
static String link(String text, String url) {
|
|
||||||
return "[%s](%s)".formatted(text, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Markdown table.
|
|
||||||
* @param headerCaptions captions of the header
|
|
||||||
* @return the Markdown table
|
|
||||||
*/
|
|
||||||
static MarkdownTable table(String... headerCaptions) {
|
|
||||||
return new MarkdownTable(headerCaptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Markdown table.
|
|
||||||
* <p>
|
|
||||||
* The formatted table is pretty-printed, all the columns are padded with spaces to
|
|
||||||
* have a consistent look.
|
|
||||||
*
|
|
||||||
* @author Moritz Halbritter
|
|
||||||
*/
|
|
||||||
static class MarkdownTable {
|
|
||||||
|
|
||||||
private final List<String> headerCaptions;
|
|
||||||
|
|
||||||
private final List<List<String>> rows;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new table with the given header captions.
|
|
||||||
* @param headerCaptions the header captions
|
|
||||||
*/
|
|
||||||
MarkdownTable(String... headerCaptions) {
|
|
||||||
this.headerCaptions = List.of(headerCaptions);
|
|
||||||
this.rows = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new row with the given cells.
|
|
||||||
* @param cells the cells to add
|
|
||||||
* @throws IllegalArgumentException if the cell size doesn't match the number of
|
|
||||||
* header captions
|
|
||||||
*/
|
|
||||||
void addRow(String... cells) {
|
|
||||||
if (cells.length != this.headerCaptions.size()) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Expected %d cells, got %d".formatted(this.headerCaptions.size(), cells.length));
|
|
||||||
}
|
|
||||||
this.rows.add(List.of(cells));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the whole table as Markdown.
|
|
||||||
* @return the table formatted as Markdown.
|
|
||||||
*/
|
|
||||||
String toMarkdown() {
|
|
||||||
int[] columnMaxLengths = calculateMaxColumnLengths();
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
writeHeader(result, columnMaxLengths);
|
|
||||||
writeHeaderSeparator(result, columnMaxLengths);
|
|
||||||
writeRows(result, columnMaxLengths);
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeHeader(StringBuilder result, int[] columnMaxLengths) {
|
|
||||||
for (int i = 0; i < this.headerCaptions.size(); i++) {
|
|
||||||
result.append((i > 0) ? " " : "| ")
|
|
||||||
.append(pad(this.headerCaptions.get(i), columnMaxLengths[i]))
|
|
||||||
.append(" |");
|
|
||||||
}
|
|
||||||
result.append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeHeaderSeparator(StringBuilder result, int[] columnMaxLengths) {
|
|
||||||
for (int i = 0; i < this.headerCaptions.size(); i++) {
|
|
||||||
result.append((i > 0) ? " " : "| ").append("-".repeat(columnMaxLengths[i])).append(" |");
|
|
||||||
}
|
|
||||||
result.append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeRows(StringBuilder result, int[] columnMaxLengths) {
|
|
||||||
for (List<String> row : this.rows) {
|
|
||||||
for (int i = 0; i < row.size(); i++) {
|
|
||||||
result.append((i > 0) ? " " : "| ").append(pad(row.get(i), columnMaxLengths[i])).append(" |");
|
|
||||||
}
|
|
||||||
result.append(System.lineSeparator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] calculateMaxColumnLengths() {
|
|
||||||
int[] columnMaxLengths = new int[this.headerCaptions.size()];
|
|
||||||
for (int i = 0; i < this.headerCaptions.size(); i++) {
|
|
||||||
columnMaxLengths[i] = this.headerCaptions.get(i).length();
|
|
||||||
}
|
|
||||||
for (List<String> row : this.rows) {
|
|
||||||
for (int i = 0; i < row.size(); i++) {
|
|
||||||
String cell = row.get(i);
|
|
||||||
if (cell.length() > columnMaxLengths[i]) {
|
|
||||||
columnMaxLengths[i] = cell.length();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return columnMaxLengths;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String pad(String input, int length) {
|
|
||||||
return input + " ".repeat(length - input.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
### Docker Compose support
|
### Docker Compose support
|
||||||
|
|
||||||
This project contains a Docker Compose file named `compose.yaml`.
|
This project contains a Docker Compose file named `compose.yaml`.
|
||||||
|
{{#services.size}}
|
||||||
{{#serviceTable}}
|
|
||||||
In this file, the following services have been defined:
|
In this file, the following services have been defined:
|
||||||
|
|
||||||
{{serviceTable}}
|
{{#services}}
|
||||||
|
* {{name}}: [`{{image}}:{{imageTag}}`]({{imageWebsite}})
|
||||||
|
{{/services}}
|
||||||
|
|
||||||
Please review the tags of the used images and set them to the same as you're running in production.
|
Please review the tags of the used images and set them to the same as you're running in production.
|
||||||
{{/serviceTable}}
|
{{/services.size}}{{^services}}
|
||||||
{{^serviceTable}}
|
|
||||||
However, no services were found. As of now, the application won't start!
|
However, no services were found. As of now, the application won't start!
|
||||||
|
|
||||||
Please make sure to add at least one service in the `compose.yaml` file.
|
Please make sure to add at least one service in the `compose.yaml` file.
|
||||||
{{/serviceTable}}
|
{{/services}}
|
||||||
@@ -31,24 +31,27 @@ import org.junit.jupiter.api.Test;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DockerComposeHelpDocumentCustomizer}.
|
* Tests for {@link ComposeHelpDocumentCustomizer}.
|
||||||
*
|
*
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
class DockerComposeHelpDocumentCustomizerTests {
|
class ComposeHelpDocumentCustomizerTests {
|
||||||
|
|
||||||
private DockerComposeHelpDocumentCustomizer customizer;
|
private ComposeHelpDocumentCustomizer customizer;
|
||||||
|
|
||||||
private ComposeFile dockerComposeFile;
|
private ComposeFile dockerComposeFile;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
this.dockerComposeFile = new ComposeFile();
|
this.dockerComposeFile = new ComposeFile();
|
||||||
this.customizer = new DockerComposeHelpDocumentCustomizer(this.dockerComposeFile);
|
this.customizer = new ComposeHelpDocumentCustomizer(this.dockerComposeFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void addsDockerComposeSection() throws IOException {
|
void addsDockerComposeSection() throws IOException {
|
||||||
|
this.dockerComposeFile.services()
|
||||||
|
.add("test2", (service) -> service.imageAndTag("image-2:4.5.6").imageWebsite("https:/example.com/image-2"));
|
||||||
this.dockerComposeFile.services()
|
this.dockerComposeFile.services()
|
||||||
.add("test", (service) -> service.imageAndTag("image-1:1.2.3").imageWebsite("https:/example.com/image-1"));
|
.add("test", (service) -> service.imageAndTag("image-1:1.2.3").imageWebsite("https:/example.com/image-1"));
|
||||||
HelpDocument helpDocument = helpDocument();
|
HelpDocument helpDocument = helpDocument();
|
||||||
@@ -60,15 +63,11 @@ class DockerComposeHelpDocumentCustomizerTests {
|
|||||||
helpDocument.write(new PrintWriter(stringWriter));
|
helpDocument.write(new PrintWriter(stringWriter));
|
||||||
assertThat(stringWriter.toString()).isEqualToIgnoringNewLines("""
|
assertThat(stringWriter.toString()).isEqualToIgnoringNewLines("""
|
||||||
### Docker Compose support
|
### Docker Compose support
|
||||||
|
|
||||||
This project contains a Docker Compose file named `compose.yaml`.
|
This project contains a Docker Compose file named `compose.yaml`.
|
||||||
|
|
||||||
In this file, the following services have been defined:
|
In this file, the following services have been defined:
|
||||||
|
|
||||||
| Service name | Image | Tag | Website |
|
* test: [`image-1:1.2.3`](https:/example.com/image-1)
|
||||||
| ------------ | --------- | ------- | ------------------------------------- |
|
* test2: [`image-2:4.5.6`](https:/example.com/image-2)
|
||||||
| test | `image-1` | `1.2.3` | [Website](https:/example.com/image-1) |
|
|
||||||
|
|
||||||
|
|
||||||
Please review the tags of the used images and set them to the same as you're running in production.""");
|
Please review the tags of the used images and set them to the same as you're running in production.""");
|
||||||
}
|
}
|
||||||
@@ -89,7 +88,6 @@ class DockerComposeHelpDocumentCustomizerTests {
|
|||||||
* No Docker Compose services found. As of now, the application won't start! Please add at least one service to the `compose.yaml` file.
|
* No Docker Compose services found. As of now, the application won't start! Please add at least one service to the `compose.yaml` file.
|
||||||
|
|
||||||
### Docker Compose support
|
### Docker Compose support
|
||||||
|
|
||||||
This project contains a Docker Compose file named `compose.yaml`.
|
This project contains a Docker Compose file named `compose.yaml`.
|
||||||
|
|
||||||
However, no services were found. As of now, the application won't start!
|
However, no services were found. As of now, the application won't start!
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2023 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.spring.initializr.generator.spring.container.docker.compose;
|
|
||||||
|
|
||||||
import io.spring.initializr.generator.spring.container.docker.compose.Markdown.MarkdownTable;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link Markdown}.
|
|
||||||
*
|
|
||||||
* @author Moritz Halbritter
|
|
||||||
*/
|
|
||||||
class MarkdownTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldFormatCode() {
|
|
||||||
String code = Markdown.code("c = a + b");
|
|
||||||
assertThat(code).isEqualTo("`c = a + b`");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldFormatLink() {
|
|
||||||
String link = Markdown.link("Spring Website", "https://spring.io/");
|
|
||||||
assertThat(link).isEqualTo("[Spring Website](https://spring.io/)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldFormatCorrectly() {
|
|
||||||
MarkdownTable table = new MarkdownTable("a", "b1", "c22", "d333");
|
|
||||||
table.addRow("0", "1", "2", "3");
|
|
||||||
table.addRow("4", "5", "6", "7");
|
|
||||||
String markdown = table.toMarkdown();
|
|
||||||
assertThat(markdown).isEqualToIgnoringNewLines("""
|
|
||||||
| a | b1 | c22 | d333 |
|
|
||||||
| - | -- | --- | ---- |
|
|
||||||
| 0 | 1 | 2 | 3 |
|
|
||||||
| 4 | 5 | 6 | 7 |
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void rowIsBiggerThanHeading() {
|
|
||||||
MarkdownTable table = new MarkdownTable("a", "b", "c", "d");
|
|
||||||
table.addRow("0.0", "1.1", "2.2", "3.3");
|
|
||||||
table.addRow("4.4", "5.5", "6.6", "7.7");
|
|
||||||
String markdown = table.toMarkdown();
|
|
||||||
assertThat(markdown).isEqualToIgnoringNewLines("""
|
|
||||||
| a | b | c | d |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| 0.0 | 1.1 | 2.2 | 3.3 |
|
|
||||||
| 4.4 | 5.5 | 6.6 | 7.7 |
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void throwsIfCellsDifferFromHeader() {
|
|
||||||
MarkdownTable table = new MarkdownTable("a", "b", "c", "d");
|
|
||||||
assertThatThrownBy(() -> table.addRow("1")).isInstanceOf(IllegalArgumentException.class)
|
|
||||||
.hasMessage("Expected 4 cells, got 1");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user