diff --git a/src/main/java/io/spring/renderer/RendererProperties.java b/src/main/java/io/spring/renderer/RendererProperties.java index c0e7c0c..3823bcf 100644 --- a/src/main/java/io/spring/renderer/RendererProperties.java +++ b/src/main/java/io/spring/renderer/RendererProperties.java @@ -17,8 +17,11 @@ package io.spring.renderer; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; +import io.spring.renderer.RendererProperties.Webhook.Category; import jakarta.validation.constraints.Pattern; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -38,6 +41,8 @@ public class RendererProperties { */ private final Map academy = new HashMap<>(); + private final Map category = new HashMap<>(); + public Github getGithub() { return this.github; } @@ -46,6 +51,10 @@ public Map getAcademy() { return this.academy; } + public Map getCategory() { + return this.category; + } + public static class Github { /** @@ -138,6 +147,26 @@ public void setDispatchToken(String dispatchToken) { this.dispatchToken = dispatchToken; } + public static class Category { + + private String displayName; + + private final Set guide = new LinkedHashSet<>(); + + public String getDisplayName() { + return this.displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public Set getGuide() { + return this.guide; + } + + } + } } diff --git a/src/main/java/io/spring/renderer/guides/GuideMetadata.java b/src/main/java/io/spring/renderer/guides/GuideMetadata.java index dccc63f..f28bc43 100644 --- a/src/main/java/io/spring/renderer/guides/GuideMetadata.java +++ b/src/main/java/io/spring/renderer/guides/GuideMetadata.java @@ -16,6 +16,8 @@ package io.spring.renderer.guides; +import java.util.Set; + import io.spring.renderer.github.Repository; /** @@ -29,9 +31,12 @@ class GuideMetadata { private final String academyUrl; - GuideMetadata(Repository repository, String academyUrl) { + private final Set category; + + GuideMetadata(Repository repository, String academyUrl, Set category) { this.repository = repository; this.academyUrl = academyUrl; + this.category = category; } public Repository getRepository() { @@ -42,4 +47,8 @@ public String getAcademyUrl() { return this.academyUrl; } + public Set getCategory() { + return this.category; + } + } diff --git a/src/main/java/io/spring/renderer/guides/GuideModel.java b/src/main/java/io/spring/renderer/guides/GuideModel.java index b421a6a..2fbcfa8 100644 --- a/src/main/java/io/spring/renderer/guides/GuideModel.java +++ b/src/main/java/io/spring/renderer/guides/GuideModel.java @@ -50,6 +50,8 @@ class GuideModel extends RepresentationModel { private String academyUrl; + private String[] category; + GuideModel(GuideMetadata guideMetadata) { Repository repository = guideMetadata.getRepository(); this.type = GuideType.fromRepositoryName(repository.getName()); @@ -76,6 +78,7 @@ class GuideModel extends RepresentationModel { this.projects = new String[0]; } this.academyUrl = guideMetadata.getAcademyUrl(); + this.category = guideMetadata.getCategory().toArray(new String[0]); } public String getName() { @@ -122,4 +125,8 @@ public String getAcademyUrl() { return this.academyUrl; } + public String[] getCategory() { + return this.category; + } + } \ No newline at end of file diff --git a/src/main/java/io/spring/renderer/guides/GuidesController.java b/src/main/java/io/spring/renderer/guides/GuidesController.java index 519420a..5109357 100644 --- a/src/main/java/io/spring/renderer/guides/GuidesController.java +++ b/src/main/java/io/spring/renderer/guides/GuidesController.java @@ -16,10 +16,14 @@ package io.spring.renderer.guides; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import io.spring.renderer.RendererProperties; +import io.spring.renderer.RendererProperties.Webhook.Category; import io.spring.renderer.github.GithubClient; import io.spring.renderer.github.GithubResourceNotFoundException; import io.spring.renderer.github.Repository; @@ -27,6 +31,7 @@ import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.MediaTypes; import org.springframework.http.ResponseEntity; +import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -51,6 +56,8 @@ public class GuidesController { private final GuideModelAssembler guideAssembler = new GuideModelAssembler(); + private Set DEFAULT_CATEGORY = Collections.singleton("Misc"); + public GuidesController(GuideRenderer guideRenderer, GithubClient github, RendererProperties properties) { this.guideRenderer = guideRenderer; this.githubClient = github; @@ -67,7 +74,7 @@ public CollectionModel listGuides() { List repositories = this.githubClient .fetchOrgRepositories(this.properties.getGithub().getOrganization()); List guideMetadataList = repositories.stream() - .map((repository) -> new GuideMetadata(repository, getAcademyUrl(repository))) + .map((repository) -> new GuideMetadata(repository, getAcademyUrl(repository), getCategory(repository))) .toList(); List guideModels = this.guideAssembler.toCollectionModel(guideMetadataList) .getContent() @@ -84,6 +91,16 @@ public CollectionModel listGuides() { return resources; } + private Set getCategory(Repository repository) { + Map category = this.properties.getCategory(); + Set values = category.values() + .stream() + .filter((v) -> v.getGuide().contains(repository.getName())) + .map(Category::getDisplayName) + .collect(Collectors.toSet()); + return (!CollectionUtils.isEmpty(values)) ? values : DEFAULT_CATEGORY; + } + private String getAcademyUrl(Repository repository) { return this.properties.getAcademy().get(repository.getName()); } @@ -97,7 +114,7 @@ public ResponseEntity showGuide(@PathVariable String type, @PathVari Repository repository = this.githubClient.fetchOrgRepository(this.properties.getGithub().getOrganization(), guideType.getPrefix() + guide); String academyUrl = this.properties.getAcademy().get(repository.getName()); - GuideMetadata guideMetadata = new GuideMetadata(repository, academyUrl); + GuideMetadata guideMetadata = new GuideMetadata(repository, academyUrl, getCategory(repository)); GuideModel guideModel = this.guideAssembler.toModel(guideMetadata); if (guideModel.getType().equals(GuideType.UNKNOWN)) { return ResponseEntity.notFound().build(); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 84c79b8..0e9d982 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,6 @@ -spring.config.import: optional:secret.properties +spring.config.import: + - optional:secret.properties + - categories.yml renderer: github: organization: spring-guides @@ -20,6 +22,7 @@ renderer: gs-rest-service: https://spring.academy/guides/rest-service gs-spring-boot: https://spring.academy/guides/building-an-application-with-spring-boot gs-messaging-rabbitmq: https://spring.academy/guides/messaging-with-rabbitmq + spring: security: user: diff --git a/src/main/resources/categories.yml b/src/main/resources/categories.yml new file mode 100644 index 0000000..2cbf325 --- /dev/null +++ b/src/main/resources/categories.yml @@ -0,0 +1,106 @@ +renderer: + category: + batch: + display-name: Batch Processing + guide: + - gs-batch-processing + - gs-spring-cloud-task + caching: + display-name: Caching + guide: + - gs-caching + cloud-platform: + display-name: Cloud Platform + guide: + - gs-spring-boot-for-azure + - gs-spring-boot-kubernetes + data: + display-name: Data Access + guide: + - gs-accessing-data-mysql + - gs-accessing-data-jpa + - gs-accessing-data-mongodb + - gs-relational-data-access + - gs-accessing-data-rest + - gs-managing-transactions + - gs-accessing-data-r2dbc + - gs-accessing-mongodb-data-rest + - gs-accessing-data-cassandra + - gs-spring-data-reactive-redis + - gs-accessing-data-neo4j + - gs-accessing-data-gemfire + io: + display-name: IO + guide: + - gs-uploading-files + - gs-async-method + - gs-validating-form-input + - gs-handling-form-submission + - gs-scheduling-tasks + messaging: + display-name: Messaging + guide: + - gs-messaging-stomp-websocket + - gs-messaging-rabbitmq + - gs-messaging-jms + - gs-messaging-gcp-pubsub + - gs-messaging-gcp-pubsub + - gs-integration + - gs-spring-cloud-stream + microservices: + display-name: Microservices + guide: + - gs-gateway + - gs-service-registration-and-discovery + - gs-spring-cloud-loadbalancer + - gs-cloud-circuit-breaker + - gs-centralized-configuration + rest: + display-name: REST APIs + guide: + - gs-accessing-neo4j-data-rest + - gs-accessing-gemfire-data-rest + - gs-rest-hateoas + - gs-reactive-rest-service + - gs-consuming-rest + - gs-rest-service + - gs-spring-boot + security: + display-name: Security + guide: + - gs-accessing-vault + - gs-vault-config + - gs-authenticating-ldap + - gs-rest-service-cors + - gs-securing-web + testing: + display-name: Testing + guide: + - gs-contract-rest + - gs-testing-web + documentation: + display-name: Documentation + guide: + - gs-testing-restdocs + web: + display-name: Web + guide: + - gs-serving-web-content + - gs-producing-web-service + - gs-consuming-web-service + packaging: + display-name: Packaging + guide: + ops: + display-name: Ops + guide: + - gs-actuator-service + streaming: + display-name: Streaming + guide: + - gs-spring-cloud-dataflow + graphql: + display-name: GraphQL + guide: + - gs-graphql-server + diff --git a/src/test/java/io/spring/renderer/guides/GuideModelTests.java b/src/test/java/io/spring/renderer/guides/GuideModelTests.java index 24f9c3f..7394ace 100644 --- a/src/test/java/io/spring/renderer/guides/GuideModelTests.java +++ b/src/test/java/io/spring/renderer/guides/GuideModelTests.java @@ -17,6 +17,7 @@ package io.spring.renderer.guides; import java.util.Arrays; +import java.util.Collections; import io.spring.renderer.github.Repository; import org.junit.jupiter.api.Test; @@ -35,7 +36,7 @@ public void nullRepositoryDescription() { "git://example.org/spring-guides/gs-sample-guide.git", "git@example.org:spring-guides/gs-sample-guide.git", "https://example.org/spring-guides/gs-sample-guide.git", null); - GuideMetadata guideMetadata = new GuideMetadata(repository, null); + GuideMetadata guideMetadata = new GuideMetadata(repository, null, Collections.singleton("test")); GuideModel guideModel = new GuideModel(guideMetadata); assertThat(guideModel.getName()).isEqualTo("sample-guide"); assertThat(guideModel.getRepositoryName()).isEqualTo("spring-guides/gs-sample-guide"); @@ -47,6 +48,7 @@ public void nullRepositoryDescription() { assertThat(guideModel.getGitUrl()).isEqualTo("git://example.org/spring-guides/gs-sample-guide.git"); assertThat(guideModel.getSshUrl()).isEqualTo("git@example.org:spring-guides/gs-sample-guide.git"); assertThat(guideModel.getProjects()).isEmpty(); + assertThat(guideModel.getCategory()).containsExactly("test"); } @Test @@ -56,7 +58,7 @@ public void noGuideProjects() { "git://example.org/spring-guides/tut-sample-guide.git", "git@example.org:spring-guides/tut-sample-guide.git", "https://example.org/spring-guides/tut-sample-guide.git", null); - GuideMetadata guideMetadata = new GuideMetadata(repository, "http://test.academy"); + GuideMetadata guideMetadata = new GuideMetadata(repository, "http://test.academy", Collections.emptySet()); GuideModel guideModel = new GuideModel(guideMetadata); assertThat(guideModel.getName()).isEqualTo("sample-guide"); assertThat(guideModel.getRepositoryName()).isEqualTo("spring-guides/tut-sample-guide"); @@ -75,7 +77,7 @@ public void withGuideProjects() { "git@example.org:spring-guides/top-sample-guide.git", "https://example.org/spring-guides/top-sample-guide.git", Arrays.asList("spring-framework", "spring-boot")); - GuideMetadata guideMetadata = new GuideMetadata(repository, null); + GuideMetadata guideMetadata = new GuideMetadata(repository, null, Collections.emptySet()); GuideModel guideModel = new GuideModel(guideMetadata); assertThat(guideModel.getName()).isEqualTo("sample-guide"); assertThat(guideModel.getRepositoryName()).isEqualTo("spring-guides/top-sample-guide"); @@ -94,7 +96,7 @@ public void deprecatedGuide() { "git@example.org:spring-guides/deprecated-gs-sample-guide.git", "https://example.org/spring-guides/deprecated-gs-sample-guide.git", Arrays.asList("spring-framework", "spring-boot")); - GuideMetadata guideMetadata = new GuideMetadata(repository, null); + GuideMetadata guideMetadata = new GuideMetadata(repository, null, Collections.emptySet()); GuideModel guideModel = new GuideModel(guideMetadata); assertThat(guideModel.getName()).isEqualTo("deprecated-gs-sample-guide"); assertThat(guideModel.getTitle()).isEqualTo("Title"); diff --git a/src/test/java/io/spring/renderer/guides/GuidesControllerTests.java b/src/test/java/io/spring/renderer/guides/GuidesControllerTests.java index cf032e5..86a5202 100644 --- a/src/test/java/io/spring/renderer/guides/GuidesControllerTests.java +++ b/src/test/java/io/spring/renderer/guides/GuidesControllerTests.java @@ -21,13 +21,17 @@ import io.spring.renderer.github.GithubClient; import io.spring.renderer.github.GithubResourceNotFoundException; import io.spring.renderer.github.Repository; +import org.hamcrest.collection.IsIterableContainingInAnyOrder; +import org.hamcrest.core.IsIterableContaining; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.util.JsonPathExpectationsHelper; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -37,6 +41,7 @@ import org.springframework.util.StringUtils; import org.springframework.web.client.HttpClientErrorException; +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -45,7 +50,8 @@ /** * Tests for {@link GuidesController} */ -@WebMvcTest(controllers = GuidesController.class, properties = "renderer.academy.gs-rest-service: http://test.com") +@WebMvcTest(controllers = GuidesController.class) +@ActiveProfiles("test") @WithMockUser public class GuidesControllerTests { @@ -60,33 +66,36 @@ public class GuidesControllerTests { @Test public void fetchAllGuides() throws Exception { - Repository restService = new Repository(12L, "gs-rest-service", "spring-guides/gs-rest-service", - "REST service sample :: Building a REST service", "http://example.org/spring-guides/gs-rest-service", - "git://example.org/spring-guides/gs-rest-service.git", - "git@example.org:spring-guides/gs-rest-service.git", - "https://example.org/spring-guides/gs-rest-service.git", + Repository restService = new Repository(12L, "gs-rest-service-test", "spring-guides/gs-rest-service-test", + "REST service sample :: Building a REST service", + "http://example.org/spring-guides/gs-rest-service-test", + "git://example.org/spring-guides/gs-rest-service-test.git", + "git@example.org:spring-guides/gs-rest-service-test.git", + "https://example.org/spring-guides/gs-rest-service-test.git", Arrays.asList("spring-boot", "spring-framework")); - Repository securingWeb = new Repository(15L, "gs-securing-web", "spring-guides/gs-securing-web", - "Securing Web :: Securing a Web Application", "http://example.org/spring-guides/gs-securing-web", - "git@example.org:spring-guides/gs-securing-web.git", - "https://example.org/spring-guides/gs-securing-web.git", - "git://example.org/spring-guides/gs-securing-web.git", null); + Repository securingWeb = new Repository(15L, "gs-securing-web-test", "spring-guides/gs-securing-web-test", + "Securing Web :: Securing a Web Application", "http://example.org/spring-guides/gs-securing-web-test", + "git@example.org:spring-guides/gs-securing-web-test.git", + "https://example.org/spring-guides/gs-securing-web-test.git", + "git://example.org/spring-guides/gs-securing-web-test.git", null); given(this.githubClient.fetchOrgRepositories("spring-guides")) .willReturn(Arrays.asList(restService, securingWeb)); this.mvc.perform(get("/guides")) .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.guides[0].name").value("rest-service")) + .andExpect(jsonPath("$._embedded.guides[0].name").value("rest-service-test")) .andExpect(jsonPath("$._embedded.guides[0].academyUrl").value("http://test.com")) + .andExpect(jsonPath("$._embedded.guides[0].category[0]").value("Test 1")) .andExpect(jsonPath("$._embedded.guides[0].projects[0]").value("spring-boot")) .andExpect(hasLink("$._embedded.guides[0]._links", "self", - "http://localhost/guides/getting-started/rest-service")) - .andExpect(jsonPath("$._embedded.guides[1].name").value("securing-web")) + "http://localhost/guides/getting-started/rest-service-test")) + .andExpect(jsonPath("$._embedded.guides[1].name").value("securing-web-test")) .andExpect(jsonPath("$._embedded.guides[1].academyUrl").isEmpty()) + .andExpect(jsonPath("$._embedded.guides[1].category").value(containsInAnyOrder("Test 1", "Test 2"))) .andExpect(jsonPath("$._embedded.guides[1].projects").isEmpty()) .andExpect(hasLink("$._embedded.guides[1]._links", "self", - "http://localhost/guides/getting-started/securing-web")); + "http://localhost/guides/getting-started/securing-web-test")); } @Test @@ -106,46 +115,64 @@ public void fetchAllGuidesFiltersUnknownTypes() throws Exception { @Test public void fetchGuide() throws Exception { - Repository restService = new Repository(12L, "gs-rest-service", "spring-guides/gs-rest-service", + Repository restService = new Repository(12L, "gs-rest-service-test", "spring-guides/gs-rest-service-test", "REST service sample :: Building a REST service :: spring-boot,spring-framework", - "http://example.org/spring-guides/gs-rest-service", - "git://example.org/spring-guides/gs-rest-service.git", - "git@example.org:spring-guides/gs-rest-service.git", - "https://example.org/spring-guides/gs-rest-service.git", + "http://example.org/spring-guides/gs-rest-service-test", + "git://example.org/spring-guides/gs-rest-service-test.git", + "git@example.org:spring-guides/gs-rest-service-test.git", + "https://example.org/spring-guides/gs-rest-service-test.git", Arrays.asList("spring-boot", "spring-framework")); - given(this.githubClient.fetchOrgRepository("spring-guides", "gs-rest-service")).willReturn(restService); + given(this.githubClient.fetchOrgRepository("spring-guides", "gs-rest-service-test")).willReturn(restService); - this.mvc.perform(get("/guides/getting-started/rest-service")) + this.mvc.perform(get("/guides/getting-started/rest-service-test")) .andExpect(status().isOk()) - .andExpect(jsonPath("$.name").value("rest-service")) - .andExpect(jsonPath("$.repositoryName").value("spring-guides/gs-rest-service")) + .andExpect(jsonPath("$.name").value("rest-service-test")) + .andExpect(jsonPath("$.repositoryName").value("spring-guides/gs-rest-service-test")) .andExpect(jsonPath("$.title").value("REST service sample")) .andExpect(jsonPath("$.description").value("Building a REST service")) .andExpect(jsonPath("$.type").value("getting-started")) - .andExpect(jsonPath("$.githubUrl").value("http://example.org/spring-guides/gs-rest-service")) - .andExpect(jsonPath("$.gitUrl").value("git://example.org/spring-guides/gs-rest-service.git")) - .andExpect(jsonPath("$.sshUrl").value("git@example.org:spring-guides/gs-rest-service.git")) - .andExpect(jsonPath("$.cloneUrl").value("https://example.org/spring-guides/gs-rest-service.git")) + .andExpect(jsonPath("$.githubUrl").value("http://example.org/spring-guides/gs-rest-service-test")) + .andExpect(jsonPath("$.gitUrl").value("git://example.org/spring-guides/gs-rest-service-test.git")) + .andExpect(jsonPath("$.sshUrl").value("git@example.org:spring-guides/gs-rest-service-test.git")) + .andExpect(jsonPath("$.cloneUrl").value("https://example.org/spring-guides/gs-rest-service-test.git")) .andExpect(jsonPath("$.academyUrl").value("http://test.com")) + .andExpect(jsonPath("$.category[0]").value("Test 1")) .andExpect(jsonPath("$.projects[0]").value("spring-boot")) - .andExpect(hasLink("self", "http://localhost/guides/getting-started/rest-service")); + .andExpect(hasLink("self", "http://localhost/guides/getting-started/rest-service-test")); } @Test public void fetchUnknownGuide() throws Exception { - Repository securingWeb = new Repository(15L, "gs-securing-web", "spring-guides/gs-securing-web", - "Securing Web :: Securing a Web Application", "http://example.org/spring-guides/gs-securing-web", - "git://example.org/spring-guides/gs-securing-web.git", - "git@example.org:spring-guides/gs-securing-web.git", - "https://example.org/spring-guides/gs-securing-web.git", null); - given(this.githubClient.fetchOrgRepository("spring-guides", "gs-rest-service")) - .willThrow(new GithubResourceNotFoundException("spring-guides", "gs-rest-service", + Repository securingWeb = new Repository(15L, "gs-securing-web-test", "spring-guides/gs-securing-web-test", + "Securing Web :: Securing a Web Application", "http://example.org/spring-guides/gs-securing-web-test", + "git://example.org/spring-guides/gs-securing-web-test.git", + "git@example.org:spring-guides/gs-securing-web-test.git", + "https://example.org/spring-guides/gs-securing-web-test.git", null); + given(this.githubClient.fetchOrgRepository("spring-guides", "gs-rest-service-test")) + .willThrow(new GithubResourceNotFoundException("spring-guides", "gs-rest-service-test", new HttpClientErrorException(HttpStatus.NOT_FOUND))); - this.mvc.perform(get("/guides/{guide}", "gs-rest-service")) + this.mvc.perform(get("/guides/{guide}", "gs-rest-service-test")) .andExpect(MockMvcResultMatchers.status().isNotFound()); } + @Test + public void fetchGuideWithUndefinedCategory() throws Exception { + Repository testService = new Repository(12L, "gs-test-service", "spring-guides/gs-test-service", + "REST service sample :: Building a REST service :: spring-boot,spring-framework", + "http://example.org/spring-guides/gs-test-service", + "git://example.org/spring-guides/gs-test-service.git", + "git@example.org:spring-guides/gs-test-service.git", + "https://example.org/spring-guides/gs-test-service.git", + Arrays.asList("spring-boot", "spring-framework")); + given(this.githubClient.fetchOrgRepository("spring-guides", "gs-test-service")).willReturn(testService); + + this.mvc.perform(get("/guides/getting-started/test-service")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.name").value("test-service")) + .andExpect(jsonPath("$.category[0]").value("Misc")); + } + @Test public void fetchGuideContent() throws Exception { GuideContentModel content = new GuideContentModel("rest-service", "content", "toc"); @@ -161,7 +188,7 @@ public void fetchGuideContent() throws Exception { @Test public void fetchUnknownGuideContent() throws Exception { given(this.guideRenderer.render(GuideType.GETTING_STARTED, "rest-service")) - .willThrow(new GithubResourceNotFoundException("spring-guides", "gs-securing-web", + .willThrow(new GithubResourceNotFoundException("spring-guides", "gs-securing-web-test", new HttpClientErrorException(HttpStatus.NOT_FOUND))); this.mvc.perform(get("/guides/getting-started/rest-service/content")) .andExpect(MockMvcResultMatchers.status().isNotFound()); diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..87a81fa --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,13 @@ +renderer: + academy: + gs-rest-service-test: http://test.com + category: + test-1: + display-name: Test 1 + guide: + - gs-rest-service-test + - gs-securing-web-test + test-2: + display-name: Test 2 + guide: + - gs-securing-web-test \ No newline at end of file