Move REST API Doc build in docs/ (#1492)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2023-11-29 09:52:40 +02:00
committed by GitHub
parent ad876720e8
commit b362698af8
9 changed files with 192 additions and 127 deletions

4
docs/.gitignore vendored
View File

@@ -6,8 +6,8 @@ content/rest-api/*.yaml
node_modules
package.json
package-lock.json
# themse
themes
# themes
themes/hugo-material-docs
# hugo
public
.hugo_build.lock

View File

@@ -1,6 +1,6 @@
<!--
Copyright (c) 2018 Bosch Software Innovations GmbH and others
Copyright (c) 2023 Bosch.IO GmbH and others
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
@@ -16,8 +16,9 @@
<artifactId>hawkbit-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>docs</artifactId>
<packaging>pom</packaging>
<!-- <packaging>pom</packaging>-->
<name>hawkBit :: Documentation</name>
<description>Documentation for hawkBit</description>
@@ -56,43 +57,6 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-openapi</id>
<phase>prepare-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-update-server</artifactId>
<version>${project.version}</version>
<classifier>mgmt-openapi</classifier>
<type>yaml</type>
<overWrite>true</overWrite>
<outputDirectory>${basedir}/content/rest-api</outputDirectory>
<destFileName>mgmt.yaml</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-update-server</artifactId>
<version>${project.version}</version>
<classifier>ddi-openapi</classifier>
<type>yaml</type>
<overWrite>true</overWrite>
<outputDirectory>${basedir}/content/rest-api</outputDirectory>
<destFileName>ddi.yaml</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
@@ -162,4 +126,29 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-test</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2023 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.doc;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* A {@link SpringBootApplication} annotated class with a main method to start.
* The minimal configuration for the stand alone hawkBit server.
*
*/
@SpringBootApplication
@EnableHawkbitManagedSecurityConfiguration
// Exception squid:S1118 - Spring boot standard behavior
@SuppressWarnings({ "squid:S1118" })
public class Start {
/**
* Main method to start the spring-boot application.
*
* @param args
* the VM arguments.
*/
// Exception squid:S2095 - Spring boot standard behavior
@SuppressWarnings({ "squid:S2095" })
public static void main(final String[] args) {
SpringApplication.run(Start.class, args);
}
}

View File

@@ -0,0 +1,41 @@
#
# Copyright (c) 2023 Bosch.IO GmbH and others
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# User Security
spring.security.user.name=admin
spring.security.user.password={noop}admin
spring.main.allow-bean-definition-overriding=true
# Http Encoding
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
# DDI authentication configuration
hawkbit.server.ddi.security.authentication.anonymous.enabled=false
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
# Optional events
hawkbit.server.repository.publish-target-poll-event=false
## Configuration for DMF/RabbitMQ integration
hawkbit.dmf.rabbitmq.enabled=false
# Swagger Configuration
#springdoc.swagger-ui.path=/update-server-documentation
#springdoc.api-docs.path=/update-server-api-docs
springdoc.show-oauth2-endpoints=true
springdoc.api-docs.version=openapi_3_0
springdoc.show-login-endpoint=true
springdoc.packages-to-scan=org.eclipse.hawkbit.mgmt,org.eclipse.hawkbit.ddi
springdoc.swagger-ui.oauth2RedirectUrl=/login/oauth2/code/suite
springdoc.paths-to-exclude=/system/**

View File

@@ -0,0 +1,14 @@
______ _ _ _ _ ____ _ _
| ____| | (_) | | | | | _ \(_) |
| |__ ___| |_ _ __ ___ ___ | |__ __ ___ _| | _| |_) |_| |_
| __| / __| | | '_ \/ __|/ _ \ | '_ \ / _` \ \ /\ / / |/ / _ <| | __|
| |___| (__| | | |_) \__ \ __/ | | | | (_| |\ V V /| <| |_) | | |_
|______\___|_|_| .__/|___/\___| |_| |_|\__,_| \_/\_/ |_|\_\____/|_|\__|
| |
|_|
Eclipse hawkBit Update Server ${application.formatted-version}
using Spring Boot ${spring-boot.formatted-version}
Go to https://www.eclipse.org/hawkbit for more information.

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<!-- Security Log with hints on potential attacks -->
<logger name="server-security" level="INFO" />
<!-- Suppressing "More than one Servlet Mapping defined. WebSocket may not work"
error due to the way VaadinServletConfiguration configures the endpoints mapping ("/UI" and "/UI/*").
At the end only the first "/UI" is taken for websocket communication. -->
<logger name="org.atmosphere.util.IOUtils" level="OFF" />
<Root level="INFO">
<appender-ref ref="CONSOLE" />
</Root>
</configuration>

View File

@@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.app;
package org.eclipse.hawkbit.doc;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
@@ -36,9 +36,11 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith({SharedSqlTestDatabaseExtension.class})
class RestApiDocTest {
private static final String MANAGEMENT_PREFIX = "mgmt-openapi";
private static final String DDI_PREFIX = "ddi-openapi";
private static final String TARGET_DIRECTORY = "target/rest-api/";
private static final String MANAGEMENT_PREFIX = "mgmt";
private static final String DDI_PREFIX = "ddi";
private static final String TARGET_DIRECTORY = "content/rest-api/";
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@LocalServerPort
private int port;
@@ -46,39 +48,37 @@ class RestApiDocTest {
@Autowired
private TestRestTemplate restTemplate;
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
void openapiJson() throws IOException {
ResponseEntity<String> response =
final ResponseEntity<String> response =
restTemplate.getForEntity("http://localhost:" + port + "/v3/api-docs", String.class);
String openapiDoc = response.getBody();
final String openapiDoc = response.getBody();
assertThat(openapiDoc).isNotNull();
splitDocumentation(openapiDoc);
}
private void splitDocumentation(String json) throws IOException {
private static void splitDocumentation(final String json) throws IOException {
processDocumentation(json, true);
processDocumentation(json, false);
}
private void processDocumentation(String json, boolean isMgmt) throws IOException {
JsonNode rootNode = objectMapper.readTree(json);
private static void processDocumentation(final String json, final boolean isMgmt) throws IOException {
final JsonNode rootNode = OBJECT_MAPPER.readTree(json);
updateJsonNodeForApi(rootNode, isMgmt);
saveDocumentation(rootNode, isMgmt);
}
private void updateJsonNodeForApi(JsonNode rootNode, boolean isMgmt) {
private static void updateJsonNodeForApi(final JsonNode rootNode, final boolean isMgmt) {
removeTags(rootNode, isMgmt);
removePaths(rootNode, isMgmt);
removeComponents(rootNode, isMgmt);
}
private void removeTags(JsonNode rootNode, boolean isMgmt) {
ArrayNode tagsNode = (ArrayNode) rootNode.get("tags");
ArrayNode modifiedTagsNode = objectMapper.createArrayNode();
private static void removeTags(final JsonNode rootNode, final boolean isMgmt) {
final ArrayNode tagsNode = (ArrayNode) rootNode.get("tags");
final ArrayNode modifiedTagsNode = OBJECT_MAPPER.createArrayNode();
for (JsonNode tagNode : tagsNode) {
for (final JsonNode tagNode : tagsNode) {
String tagName = tagNode.get("name").asText();
if (isMgmt != tagName.startsWith("DDI")) {
modifiedTagsNode.add(tagNode);
@@ -87,17 +87,17 @@ class RestApiDocTest {
((ObjectNode) rootNode).set("tags", modifiedTagsNode);
}
private void removePaths(JsonNode rootNode, boolean isMgmt) {
ObjectNode pathsNode = (ObjectNode) rootNode.get("paths");
List<String> fieldsToRemove = new ArrayList<>();
private static void removePaths(final JsonNode rootNode, final boolean isMgmt) {
final ObjectNode pathsNode = (ObjectNode) rootNode.get("paths");
final List<String> fieldsToRemove = new ArrayList<>();
pathsNode.fieldNames().forEachRemaining(fieldName -> {
JsonNode pathNode = pathsNode.get(fieldName);
final JsonNode pathNode = pathsNode.get(fieldName);
pathNode.fieldNames().forEachRemaining(path -> {
JsonNode methodNode = pathNode.get(path);
JsonNode tagsNode = methodNode.get("tags");
final JsonNode methodNode = pathNode.get(path);
final JsonNode tagsNode = methodNode.get("tags");
if (tagsNode != null) {
for (JsonNode tagNode : tagsNode) {
String tag = tagNode.asText();
final String tag = tagNode.asText();
if (isMgmt == tag.startsWith("DDI")) {
fieldsToRemove.add(fieldName);
break;
@@ -109,8 +109,8 @@ class RestApiDocTest {
fieldsToRemove.forEach(pathsNode::remove);
}
private void removeComponents(JsonNode rootNode, boolean isMgmt) {
ObjectNode schemasNode = (ObjectNode) rootNode.get("components").get("schemas");
private static void removeComponents(final JsonNode rootNode, final boolean isMgmt) {
final ObjectNode schemasNode = (ObjectNode) rootNode.get("components").get("schemas");
List<String> fieldsToRemove = new ArrayList<>();
schemasNode.fieldNames().forEachRemaining(fieldName -> {
@@ -121,7 +121,7 @@ class RestApiDocTest {
fieldsToRemove.forEach(schemasNode::remove);
}
private boolean shouldDeleteComponent(String fieldName, boolean isMgmt) {
private static boolean shouldDeleteComponent(final String fieldName, final boolean isMgmt) {
if (isMgmt) {
return fieldName.startsWith("Ddi");
}
@@ -129,25 +129,25 @@ class RestApiDocTest {
}
private void saveDocumentation(JsonNode rootNode, boolean isMgmt) throws IOException {
String prefix = isMgmt ? MANAGEMENT_PREFIX : DDI_PREFIX;
private static void saveDocumentation(final JsonNode rootNode, final boolean isMgmt) throws IOException {
final String prefix = isMgmt ? MANAGEMENT_PREFIX : DDI_PREFIX;
saveAsJson(rootNode, prefix);
saveAsYaml(rootNode, prefix);
}
private void saveAsJson(JsonNode rootNode, String prefix) throws IOException {
Path targetPath = getTargetPath(prefix, ".json");
Files.writeString(targetPath, objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode));
private static void saveAsJson(final JsonNode rootNode, final String prefix) throws IOException {
final Path targetPath = getTargetPath(prefix, ".json");
Files.writeString(targetPath, OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode));
}
private void saveAsYaml(JsonNode rootNode, String prefix) throws IOException {
YAMLMapper yamlMapper = new YAMLMapper();
Path targetPath = getTargetPath(prefix, ".yaml");
private static void saveAsYaml(final JsonNode rootNode, final String prefix) throws IOException {
final YAMLMapper yamlMapper = new YAMLMapper();
final Path targetPath = getTargetPath(prefix, ".yaml");
Files.writeString(targetPath, yamlMapper.writeValueAsString(rootNode));
}
private Path getTargetPath(String prefix, String extension) throws IOException {
Path targetPath = Paths.get(TARGET_DIRECTORY + prefix + extension);
private static Path getTargetPath(final String prefix, final String extension) throws IOException {
final Path targetPath = Paths.get(TARGET_DIRECTORY + prefix + extension);
Files.createDirectories(targetPath.getParent());
return targetPath;
}

View File

@@ -32,56 +32,6 @@
</plugins>
</build>
</profile>
<profile>
<id>attach-artifacts-profile</id>
<!-- This profile activates when -DskipTests is not provided -->
<activation>
<property>
<name>!skipTests</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/rest-api/mgmt-openapi.json</file>
<type>json</type>
<classifier>mgmt-openapi</classifier>
</artifact>
<artifact>
<file>${project.build.directory}/rest-api/mgmt-openapi.yaml</file>
<type>yaml</type>
<classifier>mgmt-openapi</classifier>
</artifact>
<artifact>
<file>${project.build.directory}/rest-api/ddi-openapi.json</file>
<type>json</type>
<classifier>ddi-openapi</classifier>
</artifact>
<artifact>
<file>${project.build.directory}/rest-api/ddi-openapi.yaml</file>
<type>yaml</type>
<classifier>ddi-openapi</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>